Repository: VirtueSky/sunflower Branch: main Commit: 58d97baec1c0 Files: 2099 Total size: 3.6 MB Directory structure: gitextract_ddb6gc8r/ ├── .github/ │ └── workflows/ │ └── notify-discord-on-release.yml ├── LICENSE ├── LICENSE.meta ├── README.md ├── README.md.meta ├── VirtueSky/ │ ├── Advertising/ │ │ ├── Editor/ │ │ │ ├── AdSettingEditor.cs │ │ │ ├── AdSettingEditor.cs.meta │ │ │ ├── AdsWindowEditor.cs │ │ │ ├── AdsWindowEditor.cs.meta │ │ │ ├── Virtuesky.Sunflower.Advertising.Editor.asmdef │ │ │ └── Virtuesky.Sunflower.Advertising.Editor.asmdef.meta │ │ ├── Editor.meta │ │ ├── Runtime/ │ │ │ ├── Admob/ │ │ │ │ ├── AdmobAdClient.cs │ │ │ │ ├── AdmobAdClient.cs.meta │ │ │ │ ├── AdmobAdUnitVariable.cs │ │ │ │ ├── AdmobAdUnitVariable.cs.meta │ │ │ │ ├── AdmodUnitVariable/ │ │ │ │ │ ├── AdmobAppOpenVariable.cs │ │ │ │ │ ├── AdmobAppOpenVariable.cs.meta │ │ │ │ │ ├── AdmobBannerVariable.cs │ │ │ │ │ ├── AdmobBannerVariable.cs.meta │ │ │ │ │ ├── AdmobInterVariable.cs │ │ │ │ │ ├── AdmobInterVariable.cs.meta │ │ │ │ │ ├── AdmobNativeOverlayVariable.cs │ │ │ │ │ ├── AdmobNativeOverlayVariable.cs.meta │ │ │ │ │ ├── AdmobRewardInterVariable.cs │ │ │ │ │ ├── AdmobRewardInterVariable.cs.meta │ │ │ │ │ ├── AdmobRewardVariable.cs │ │ │ │ │ └── AdmobRewardVariable.cs.meta │ │ │ │ └── AdmodUnitVariable.meta │ │ │ ├── Admob.meta │ │ │ ├── General/ │ │ │ │ ├── AdClient.cs │ │ │ │ ├── AdClient.cs.meta │ │ │ │ ├── AdInfo.cs │ │ │ │ ├── AdInfo.cs.meta │ │ │ │ ├── AdSetting.cs │ │ │ │ ├── AdSetting.cs.meta │ │ │ │ ├── AdStatic.cs │ │ │ │ ├── AdStatic.cs.meta │ │ │ │ ├── AdUnitVariable.cs │ │ │ │ ├── AdUnitVariable.cs.meta │ │ │ │ ├── Advertising.cs │ │ │ │ ├── Advertising.cs.meta │ │ │ │ ├── IAdUnit.cs │ │ │ │ └── IAdUnit.cs.meta │ │ │ ├── General.meta │ │ │ ├── LevelPlay/ │ │ │ │ ├── LevelPlayAdClient.cs │ │ │ │ ├── LevelPlayAdClient.cs.meta │ │ │ │ ├── LevelPlayAdUnitVariable.cs │ │ │ │ ├── LevelPlayAdUnitVariable.cs.meta │ │ │ │ ├── LevelPlayUnitVariable/ │ │ │ │ │ ├── LevelPlayBannerVariable.cs │ │ │ │ │ ├── LevelPlayBannerVariable.cs.meta │ │ │ │ │ ├── LevelPlayInterVariable.cs │ │ │ │ │ ├── LevelPlayInterVariable.cs.meta │ │ │ │ │ ├── LevelPlayRewardVariable.cs │ │ │ │ │ └── LevelPlayRewardVariable.cs.meta │ │ │ │ └── LevelPlayUnitVariable.meta │ │ │ ├── LevelPlay.meta │ │ │ ├── Max/ │ │ │ │ ├── MaxAdClient.cs │ │ │ │ ├── MaxAdClient.cs.meta │ │ │ │ ├── MaxAdUnitVariable.cs │ │ │ │ ├── MaxAdUnitVariable.cs.meta │ │ │ │ ├── MaxUnitVariable/ │ │ │ │ │ ├── MaxAppOpenVariable.cs │ │ │ │ │ ├── MaxAppOpenVariable.cs.meta │ │ │ │ │ ├── MaxBannerVariable.cs │ │ │ │ │ ├── MaxBannerVariable.cs.meta │ │ │ │ │ ├── MaxInterVariable.cs │ │ │ │ │ ├── MaxInterVariable.cs.meta │ │ │ │ │ ├── MaxRewardVariable.cs │ │ │ │ │ └── MaxRewardVariable.cs.meta │ │ │ │ └── MaxUnitVariable.meta │ │ │ ├── Max.meta │ │ │ ├── Virtuesky.Sunflower.Advertising.asmdef │ │ │ └── Virtuesky.Sunflower.Advertising.asmdef.meta │ │ └── Runtime.meta │ ├── Advertising.meta │ ├── AssetFinder/ │ │ ├── Editor/ │ │ │ ├── Script/ │ │ │ │ ├── AssetFinder.cs │ │ │ │ ├── AssetFinder.cs.meta │ │ │ │ ├── AssetFinderAssetType.cs │ │ │ │ ├── AssetFinderAssetType.cs.meta │ │ │ │ ├── AssetFinderCacheEditor.cs │ │ │ │ ├── AssetFinderCacheEditor.cs.meta │ │ │ │ ├── AssetFinderDuplicate.cs │ │ │ │ ├── AssetFinderDuplicate.cs.meta │ │ │ │ ├── AssetFinderRef.cs │ │ │ │ ├── AssetFinderRef.cs.meta │ │ │ │ ├── AssetFinderWindowExtension.cs │ │ │ │ ├── AssetFinderWindowExtension.cs.meta │ │ │ │ ├── Core/ │ │ │ │ │ ├── AssetFinderAsset.AssetState.cs │ │ │ │ │ ├── AssetFinderAsset.AssetState.cs.meta │ │ │ │ │ ├── AssetFinderAsset.AssetType.cs │ │ │ │ │ ├── AssetFinderAsset.AssetType.cs.meta │ │ │ │ │ ├── AssetFinderAsset.Classes.cs │ │ │ │ │ ├── AssetFinderAsset.Classes.cs.meta │ │ │ │ │ ├── AssetFinderAsset.Constants.cs │ │ │ │ │ ├── AssetFinderAsset.Constants.cs.meta │ │ │ │ │ ├── AssetFinderAsset.ContentLoader.cs │ │ │ │ │ ├── AssetFinderAsset.ContentLoader.cs.meta │ │ │ │ │ ├── AssetFinderAsset.Drawing.cs │ │ │ │ │ ├── AssetFinderAsset.Drawing.cs.meta │ │ │ │ │ ├── AssetFinderAsset.FileInfo.cs │ │ │ │ │ ├── AssetFinderAsset.FileInfo.cs.meta │ │ │ │ │ ├── AssetFinderAsset.GuidManager.cs │ │ │ │ │ ├── AssetFinderAsset.GuidManager.cs.meta │ │ │ │ │ ├── AssetFinderAsset.PathInfo.cs │ │ │ │ │ ├── AssetFinderAsset.PathInfo.cs.meta │ │ │ │ │ ├── AssetFinderAsset.cs │ │ │ │ │ ├── AssetFinderAsset.cs.meta │ │ │ │ │ ├── AssetFinderAutoRefreshMode.cs │ │ │ │ │ ├── AssetFinderAutoRefreshMode.cs.meta │ │ │ │ │ ├── AssetFinderCache.AssetSearch.cs │ │ │ │ │ ├── AssetFinderCache.AssetSearch.cs.meta │ │ │ │ │ ├── AssetFinderCache.AsyncProcessor.cs │ │ │ │ │ ├── AssetFinderCache.AsyncProcessor.cs.meta │ │ │ │ │ ├── AssetFinderCache.Constants.cs │ │ │ │ │ ├── AssetFinderCache.Constants.cs.meta │ │ │ │ │ ├── AssetFinderCache.Lifecycle.cs │ │ │ │ │ ├── AssetFinderCache.Lifecycle.cs.meta │ │ │ │ │ ├── AssetFinderCache.ProjectManager.cs │ │ │ │ │ ├── AssetFinderCache.ProjectManager.cs.meta │ │ │ │ │ ├── AssetFinderCache.Scanner.cs │ │ │ │ │ ├── AssetFinderCache.Scanner.cs.meta │ │ │ │ │ ├── AssetFinderCache.Search.cs │ │ │ │ │ ├── AssetFinderCache.Search.cs.meta │ │ │ │ │ ├── AssetFinderCache.cs │ │ │ │ │ ├── AssetFinderCache.cs.meta │ │ │ │ │ ├── AssetFinderGitUtil.cs │ │ │ │ │ ├── AssetFinderGitUtil.cs.meta │ │ │ │ │ ├── AssetFinderNavigationHistory.cs │ │ │ │ │ ├── AssetFinderNavigationHistory.cs.meta │ │ │ │ │ ├── AssetFinderSelectionManager.cs │ │ │ │ │ ├── AssetFinderSelectionManager.cs.meta │ │ │ │ │ ├── AssetFinderSettingExt.cs │ │ │ │ │ ├── AssetFinderSettingExt.cs.meta │ │ │ │ │ ├── AssetFinderSmartLock.cs │ │ │ │ │ ├── AssetFinderSmartLock.cs.meta │ │ │ │ │ ├── AssetFinderWindowFocus.cs │ │ │ │ │ └── AssetFinderWindowFocus.cs.meta │ │ │ │ ├── Core.meta │ │ │ │ ├── Dev/ │ │ │ │ │ ├── AssetFinderDefine.cs │ │ │ │ │ ├── AssetFinderDefine.cs.meta │ │ │ │ │ ├── AssetFinderDev.cs │ │ │ │ │ ├── AssetFinderDev.cs.meta │ │ │ │ │ ├── AssetFinderReferenceValidator.cs │ │ │ │ │ ├── AssetFinderReferenceValidator.cs.meta │ │ │ │ │ ├── AssetFinderWindowAll.Validator.cs │ │ │ │ │ └── AssetFinderWindowAll.Validator.cs.meta │ │ │ │ ├── Dev.meta │ │ │ │ ├── Drawer/ │ │ │ │ │ ├── AssetFinderAddressableDrawer.cs │ │ │ │ │ ├── AssetFinderAddressableDrawer.cs.meta │ │ │ │ │ ├── AssetFinderAssetGroup.cs │ │ │ │ │ ├── AssetFinderAssetGroup.cs.meta │ │ │ │ │ ├── AssetFinderAssetGroupDrawer.cs │ │ │ │ │ ├── AssetFinderAssetGroupDrawer.cs.meta │ │ │ │ │ ├── AssetFinderAssetOrganizer.cs │ │ │ │ │ ├── AssetFinderAssetOrganizer.cs.meta │ │ │ │ │ ├── AssetFinderBookmark.cs │ │ │ │ │ ├── AssetFinderBookmark.cs.meta │ │ │ │ │ ├── AssetFinderDeleteEmptyFolder.cs │ │ │ │ │ ├── AssetFinderDeleteEmptyFolder.cs.meta │ │ │ │ │ ├── AssetFinderIgnoreDrawer.cs │ │ │ │ │ ├── AssetFinderIgnoreDrawer.cs.meta │ │ │ │ │ ├── AssetFinderMissingReference.cs │ │ │ │ │ ├── AssetFinderMissingReference.cs.meta │ │ │ │ │ ├── AssetFinderSetting.cs │ │ │ │ │ ├── AssetFinderSetting.cs.meta │ │ │ │ │ ├── AssetFinderUsedInBuild.cs │ │ │ │ │ └── AssetFinderUsedInBuild.cs.meta │ │ │ │ ├── Drawer.meta │ │ │ │ ├── Duplicate/ │ │ │ │ │ ├── AssetFinderChunk.cs │ │ │ │ │ ├── AssetFinderChunk.cs.meta │ │ │ │ │ ├── AssetFinderDuplicateTree2.cs │ │ │ │ │ ├── AssetFinderDuplicateTree2.cs.meta │ │ │ │ │ ├── AssetFinderFileCompare.cs │ │ │ │ │ ├── AssetFinderFileCompare.cs.meta │ │ │ │ │ ├── AssetFinderHead.cs │ │ │ │ │ └── AssetFinderHead.cs.meta │ │ │ │ ├── Duplicate.meta │ │ │ │ ├── Extension/ │ │ │ │ │ ├── AssetFinderExtension.cs │ │ │ │ │ ├── AssetFinderExtension.cs.meta │ │ │ │ │ ├── AssetFinderHelper.cs │ │ │ │ │ ├── AssetFinderHelper.cs.meta │ │ │ │ │ ├── AssetFinderUnity.cs │ │ │ │ │ ├── AssetFinderUnity.cs.meta │ │ │ │ │ ├── GUI2.cs │ │ │ │ │ └── GUI2.cs.meta │ │ │ │ ├── Extension.meta │ │ │ │ ├── Extensions/ │ │ │ │ │ ├── AssetFinderWindowExtensions.cs │ │ │ │ │ ├── AssetFinderWindowExtensions.cs.meta │ │ │ │ │ ├── CollectionExtensions.cs │ │ │ │ │ ├── CollectionExtensions.cs.meta │ │ │ │ │ ├── ColorExtensions.cs │ │ │ │ │ ├── ColorExtensions.cs.meta │ │ │ │ │ ├── DictionaryExtensions.cs │ │ │ │ │ ├── DictionaryExtensions.cs.meta │ │ │ │ │ ├── GameObjectExtensions.cs │ │ │ │ │ ├── GameObjectExtensions.cs.meta │ │ │ │ │ ├── RectExtensions.cs │ │ │ │ │ ├── RectExtensions.cs.meta │ │ │ │ │ ├── RectGUIExtensions.cs │ │ │ │ │ ├── RectGUIExtensions.cs.meta │ │ │ │ │ ├── SerializedObjectExtensions.cs │ │ │ │ │ ├── SerializedObjectExtensions.cs.meta │ │ │ │ │ ├── TabExtensions.cs │ │ │ │ │ ├── TabExtensions.cs.meta │ │ │ │ │ ├── UnityObjectExtensions.cs │ │ │ │ │ └── UnityObjectExtensions.cs.meta │ │ │ │ ├── Extensions.meta │ │ │ │ ├── Modules/ │ │ │ │ │ ├── Addressable/ │ │ │ │ │ │ ├── AssetFinderAddressable.ASMStatus.cs │ │ │ │ │ │ ├── AssetFinderAddressable.ASMStatus.cs.meta │ │ │ │ │ │ ├── AssetFinderAddressable.AddressInfo.cs │ │ │ │ │ │ ├── AssetFinderAddressable.AddressInfo.cs.meta │ │ │ │ │ │ ├── AssetFinderAddressable.ProjectStatus.cs │ │ │ │ │ │ ├── AssetFinderAddressable.ProjectStatus.cs.meta │ │ │ │ │ │ ├── AssetFinderAddressable.cs │ │ │ │ │ │ └── AssetFinderAddressable.cs.meta │ │ │ │ │ ├── Addressable.meta │ │ │ │ │ ├── AssetFinderCSV.cs │ │ │ │ │ ├── AssetFinderCSV.cs.meta │ │ │ │ │ ├── AssetFinderExport.cs │ │ │ │ │ ├── AssetFinderExport.cs.meta │ │ │ │ │ ├── AssetFinderSceneCache.cs │ │ │ │ │ ├── AssetFinderSceneCache.cs.meta │ │ │ │ │ ├── AssetFinderSelection.cs │ │ │ │ │ ├── AssetFinderSelection.cs.meta │ │ │ │ │ ├── Lightmap/ │ │ │ │ │ │ ├── AssetFinderLightmap.EnlightenRendererInformation.cs │ │ │ │ │ │ ├── AssetFinderLightmap.EnlightenRendererInformation.cs.meta │ │ │ │ │ │ ├── AssetFinderLightmap.EnlightenSceneMapping.cs │ │ │ │ │ │ ├── AssetFinderLightmap.EnlightenSceneMapping.cs.meta │ │ │ │ │ │ ├── AssetFinderLightmap.EnlightenSystemAtlasInformation.cs │ │ │ │ │ │ ├── AssetFinderLightmap.EnlightenSystemAtlasInformation.cs.meta │ │ │ │ │ │ ├── AssetFinderLightmap.EnlightenSystemInformation.cs │ │ │ │ │ │ ├── AssetFinderLightmap.EnlightenSystemInformation.cs.meta │ │ │ │ │ │ ├── AssetFinderLightmap.EnlightenTerrainChunksInformation.cs │ │ │ │ │ │ ├── AssetFinderLightmap.EnlightenTerrainChunksInformation.cs.meta │ │ │ │ │ │ ├── AssetFinderLightmap.LightBakingOutput.cs │ │ │ │ │ │ ├── AssetFinderLightmap.LightBakingOutput.cs.meta │ │ │ │ │ │ ├── AssetFinderLightmap.LightingDataAssetRoot.cs │ │ │ │ │ │ ├── AssetFinderLightmap.LightingDataAssetRoot.cs.meta │ │ │ │ │ │ ├── AssetFinderLightmap.LightmapData.cs │ │ │ │ │ │ ├── AssetFinderLightmap.LightmapData.cs.meta │ │ │ │ │ │ ├── AssetFinderLightmap.RendererData.cs │ │ │ │ │ │ ├── AssetFinderLightmap.RendererData.cs.meta │ │ │ │ │ │ ├── AssetFinderLightmap.SceneObjectIdentifier.cs │ │ │ │ │ │ ├── AssetFinderLightmap.SceneObjectIdentifier.cs.meta │ │ │ │ │ │ ├── AssetFinderLightmap.cs │ │ │ │ │ │ └── AssetFinderLightmap.cs.meta │ │ │ │ │ └── Lightmap.meta │ │ │ │ ├── Modules.meta │ │ │ │ ├── Monitor/ │ │ │ │ │ ├── AssetFinderCacheHelper.cs │ │ │ │ │ └── AssetFinderCacheHelper.cs.meta │ │ │ │ ├── Monitor.meta │ │ │ │ ├── TreeUI/ │ │ │ │ │ ├── AssetFinderRef.cs │ │ │ │ │ ├── AssetFinderRef.cs.meta │ │ │ │ │ ├── AssetFinderRefDrawer.Mode.cs │ │ │ │ │ ├── AssetFinderRefDrawer.Mode.cs.meta │ │ │ │ │ ├── AssetFinderRefDrawer.Sort.cs │ │ │ │ │ ├── AssetFinderRefDrawer.Sort.cs.meta │ │ │ │ │ ├── AssetFinderRefDrawer.cs │ │ │ │ │ ├── AssetFinderRefDrawer.cs.meta │ │ │ │ │ ├── AssetFinderSceneRef.cs │ │ │ │ │ ├── AssetFinderSceneRef.cs.meta │ │ │ │ │ ├── AssetFinderTreeUI2.cs │ │ │ │ │ └── AssetFinderTreeUI2.cs.meta │ │ │ │ ├── TreeUI.meta │ │ │ │ ├── UI/ │ │ │ │ │ ├── AssetFinderDeleteButton.cs │ │ │ │ │ ├── AssetFinderDeleteButton.cs.meta │ │ │ │ │ ├── AssetFinderEnumDrawer.cs │ │ │ │ │ ├── AssetFinderEnumDrawer.cs.meta │ │ │ │ │ ├── AssetFinderGUIContent.cs │ │ │ │ │ ├── AssetFinderGUIContent.cs.meta │ │ │ │ │ ├── AssetFinderIcon.cs │ │ │ │ │ ├── AssetFinderIcon.cs.meta │ │ │ │ │ ├── AssetFinderObjectDrawer.cs │ │ │ │ │ ├── AssetFinderObjectDrawer.cs.meta │ │ │ │ │ ├── AssetFinderSearchView.cs │ │ │ │ │ ├── AssetFinderSearchView.cs.meta │ │ │ │ │ ├── AssetFinderSplitView.cs │ │ │ │ │ ├── AssetFinderSplitView.cs.meta │ │ │ │ │ ├── AssetFinderTabView.cs │ │ │ │ │ ├── AssetFinderTabView.cs.meta │ │ │ │ │ ├── AssetFinderToggleList.cs │ │ │ │ │ ├── AssetFinderToggleList.cs.meta │ │ │ │ │ ├── Theme/ │ │ │ │ │ │ ├── AssetFinderTheme.Dark.cs │ │ │ │ │ │ ├── AssetFinderTheme.Dark.cs.meta │ │ │ │ │ │ ├── AssetFinderTheme.Light.cs │ │ │ │ │ │ ├── AssetFinderTheme.Light.cs.meta │ │ │ │ │ │ ├── AssetFinderTheme.cs │ │ │ │ │ │ └── AssetFinderTheme.cs.meta │ │ │ │ │ └── Theme.meta │ │ │ │ ├── UI.meta │ │ │ │ ├── Window/ │ │ │ │ │ ├── AssetFinderWindowAll.CacheManager.cs │ │ │ │ │ ├── AssetFinderWindowAll.CacheManager.cs.meta │ │ │ │ │ ├── AssetFinderWindowAll.Drawing.cs │ │ │ │ │ ├── AssetFinderWindowAll.Drawing.cs.meta │ │ │ │ │ ├── AssetFinderWindowAll.GuidManager.cs │ │ │ │ │ ├── AssetFinderWindowAll.GuidManager.cs.meta │ │ │ │ │ ├── AssetFinderWindowAll.Initialization.cs │ │ │ │ │ ├── AssetFinderWindowAll.Initialization.cs.meta │ │ │ │ │ ├── AssetFinderWindowAll.PanelSettings.cs │ │ │ │ │ ├── AssetFinderWindowAll.PanelSettings.cs.meta │ │ │ │ │ ├── AssetFinderWindowAll.SelectionManager.cs │ │ │ │ │ ├── AssetFinderWindowAll.SelectionManager.cs.meta │ │ │ │ │ ├── AssetFinderWindowAll.SettingsPanel.cs │ │ │ │ │ ├── AssetFinderWindowAll.SettingsPanel.cs.meta │ │ │ │ │ ├── AssetFinderWindowAll.ToolsPanel.cs │ │ │ │ │ ├── AssetFinderWindowAll.ToolsPanel.cs.meta │ │ │ │ │ ├── AssetFinderWindowAll.UILayout.cs │ │ │ │ │ ├── AssetFinderWindowAll.UILayout.cs.meta │ │ │ │ │ ├── AssetFinderWindowAll.cs │ │ │ │ │ ├── AssetFinderWindowAll.cs.meta │ │ │ │ │ ├── AssetFinderWindowBase.cs │ │ │ │ │ ├── AssetFinderWindowBase.cs.meta │ │ │ │ │ ├── IRefDraw.cs │ │ │ │ │ ├── IRefDraw.cs.meta │ │ │ │ │ ├── IWindow.cs │ │ │ │ │ └── IWindow.cs.meta │ │ │ │ └── Window.meta │ │ │ ├── Script.meta │ │ │ ├── Virtuesky.Sunflower.AssetFinder.Editor.asmdef │ │ │ ├── Virtuesky.Sunflower.AssetFinder.Editor.asmdef.meta │ │ │ ├── v2/ │ │ │ │ ├── AssetFinder.cs │ │ │ │ ├── AssetFinder.cs.meta │ │ │ │ ├── Core/ │ │ │ │ │ ├── AssetFinderAssetDB.cs │ │ │ │ │ ├── AssetFinderAssetDB.cs.meta │ │ │ │ │ ├── AssetFinderAssetFile.cs │ │ │ │ │ ├── AssetFinderAssetFile.cs.meta │ │ │ │ │ ├── AssetFinderCacheAsset.cs │ │ │ │ │ ├── AssetFinderCacheAsset.cs.meta │ │ │ │ │ ├── AssetFinderID.cs │ │ │ │ │ ├── AssetFinderID.cs.meta │ │ │ │ │ ├── AssetFinderIDRef.cs │ │ │ │ │ ├── AssetFinderIDRef.cs.meta │ │ │ │ │ ├── AssetFinderSceneObject.cs │ │ │ │ │ ├── AssetFinderSceneObject.cs.meta │ │ │ │ │ ├── SubAssetDetail.cs │ │ │ │ │ └── SubAssetDetail.cs.meta │ │ │ │ ├── Core.meta │ │ │ │ ├── Drawer/ │ │ │ │ │ ├── AssetFinderAssetFileDrawer.cs │ │ │ │ │ ├── AssetFinderAssetFileDrawer.cs.meta │ │ │ │ │ ├── AssetFinderCacheAssetEditor.cs │ │ │ │ │ ├── AssetFinderCacheAssetEditor.cs.meta │ │ │ │ │ ├── AssetFinderIDDrawer.cs │ │ │ │ │ └── AssetFinderIDDrawer.cs.meta │ │ │ │ ├── Drawer.meta │ │ │ │ ├── GUI/ │ │ │ │ │ ├── AssetFinderAssetGUI.cs │ │ │ │ │ ├── AssetFinderAssetGUI.cs.meta │ │ │ │ │ ├── AssetFinderAssetInfo.cs │ │ │ │ │ └── AssetFinderAssetInfo.cs.meta │ │ │ │ ├── GUI.meta │ │ │ │ ├── Parser/ │ │ │ │ │ ├── AssetFinderParser.BinaryAsset.cs │ │ │ │ │ ├── AssetFinderParser.BinaryAsset.cs.meta │ │ │ │ │ ├── AssetFinderParser.LightMap.cs │ │ │ │ │ ├── AssetFinderParser.LightMap.cs.meta │ │ │ │ │ ├── AssetFinderParser.Model3D.cs │ │ │ │ │ ├── AssetFinderParser.Model3D.cs.meta │ │ │ │ │ ├── AssetFinderParser.Shader.cs │ │ │ │ │ ├── AssetFinderParser.Shader.cs.meta │ │ │ │ │ ├── AssetFinderParser.ShaderGraph.cs │ │ │ │ │ ├── AssetFinderParser.ShaderGraph.cs.meta │ │ │ │ │ ├── AssetFinderParser.Terrain.cs │ │ │ │ │ ├── AssetFinderParser.Terrain.cs.meta │ │ │ │ │ ├── AssetFinderParser.UIToolkit.cs │ │ │ │ │ ├── AssetFinderParser.UIToolkit.cs.meta │ │ │ │ │ ├── AssetFinderParser.Yaml.cs │ │ │ │ │ ├── AssetFinderParser.Yaml.cs.meta │ │ │ │ │ ├── AssetFinderParser.cs │ │ │ │ │ └── AssetFinderParser.cs.meta │ │ │ │ ├── Parser.meta │ │ │ │ ├── UI/ │ │ │ │ │ ├── AssetRefUI.cs │ │ │ │ │ ├── AssetRefUI.cs.meta │ │ │ │ │ ├── AssetUI.cs │ │ │ │ │ ├── AssetUI.cs.meta │ │ │ │ │ ├── FileUI.cs │ │ │ │ │ ├── FileUI.cs.meta │ │ │ │ │ ├── FolderUI.cs │ │ │ │ │ └── FolderUI.cs.meta │ │ │ │ ├── UI.meta │ │ │ │ ├── Unity/ │ │ │ │ │ ├── AssetFinderInitializer.cs │ │ │ │ │ ├── AssetFinderInitializer.cs.meta │ │ │ │ │ ├── AssetFinderLightmap.cs │ │ │ │ │ ├── AssetFinderLightmap.cs.meta │ │ │ │ │ ├── AssetFinderTerrain.cs │ │ │ │ │ ├── AssetFinderTerrain.cs.meta │ │ │ │ │ ├── AssetFinderUSelection.cs │ │ │ │ │ └── AssetFinderUSelection.cs.meta │ │ │ │ ├── Unity.meta │ │ │ │ ├── Utils/ │ │ │ │ │ ├── AssetFinderTimeSlice.cs │ │ │ │ │ └── AssetFinderTimeSlice.cs.meta │ │ │ │ └── Utils.meta │ │ │ └── v2.meta │ │ └── Editor.meta │ ├── AssetFinder.meta │ ├── Audio/ │ │ ├── Editor/ │ │ │ ├── AudioWindowEditor.cs │ │ │ ├── AudioWindowEditor.cs.meta │ │ │ ├── EditorAudioPreview.cs │ │ │ ├── EditorAudioPreview.cs.meta │ │ │ ├── SoundDataEditor.cs │ │ │ ├── SoundDataEditor.cs.meta │ │ │ ├── Virtuesky.Sunflower.Audio.Editor.asmdef │ │ │ └── Virtuesky.Sunflower.Audio.Editor.asmdef.meta │ │ ├── Editor.meta │ │ ├── Runtime/ │ │ │ ├── AudioHelper.cs │ │ │ ├── AudioHelper.cs.meta │ │ │ ├── AudioManager.cs │ │ │ ├── AudioManager.cs.meta │ │ │ ├── Music_Event/ │ │ │ │ ├── PauseMusicEvent.cs │ │ │ │ ├── PauseMusicEvent.cs.meta │ │ │ │ ├── PlayMusicEvent.cs │ │ │ │ ├── PlayMusicEvent.cs.meta │ │ │ │ ├── ResumeMusicEvent.cs │ │ │ │ ├── ResumeMusicEvent.cs.meta │ │ │ │ ├── StopMusicEvent.cs │ │ │ │ └── StopMusicEvent.cs.meta │ │ │ ├── Music_Event.meta │ │ │ ├── Sfx_Event/ │ │ │ │ ├── FinishSfxEvent.cs │ │ │ │ ├── FinishSfxEvent.cs.meta │ │ │ │ ├── PauseSfxEvent.cs │ │ │ │ ├── PauseSfxEvent.cs.meta │ │ │ │ ├── PlaySfxEvent.cs │ │ │ │ ├── PlaySfxEvent.cs.meta │ │ │ │ ├── ResumeSfxEvent.cs │ │ │ │ ├── ResumeSfxEvent.cs.meta │ │ │ │ ├── StopAllSfxEvent.cs │ │ │ │ ├── StopAllSfxEvent.cs.meta │ │ │ │ ├── StopSfxEvent.cs │ │ │ │ └── StopSfxEvent.cs.meta │ │ │ ├── Sfx_Event.meta │ │ │ ├── SoundCache.cs │ │ │ ├── SoundCache.cs.meta │ │ │ ├── SoundComponent.cs │ │ │ ├── SoundComponent.cs.meta │ │ │ ├── SoundData.cs │ │ │ ├── SoundData.cs.meta │ │ │ ├── Volume_Variable/ │ │ │ │ ├── MusicVolumeChange.cs │ │ │ │ ├── MusicVolumeChange.cs.meta │ │ │ │ ├── SfxVolumeChange.cs │ │ │ │ └── SfxVolumeChange.cs.meta │ │ │ ├── Volume_Variable.meta │ │ │ ├── virtuesky.sunflower.audio.asmdef │ │ │ └── virtuesky.sunflower.audio.asmdef.meta │ │ └── Runtime.meta │ ├── Audio.meta │ ├── Button/ │ │ ├── Editor/ │ │ │ ├── ButtomCustomEditor.cs │ │ │ ├── ButtomCustomEditor.cs.meta │ │ │ ├── Virtuesky.Sunflower.Button.Editor.asmdef │ │ │ └── Virtuesky.Sunflower.Button.Editor.asmdef.meta │ │ ├── Editor.meta │ │ ├── Runtime/ │ │ │ ├── ButtonCustom.cs │ │ │ ├── ButtonCustom.cs.meta │ │ │ ├── ButtonTMP.cs │ │ │ ├── ButtonTMP.cs.meta │ │ │ ├── ButtonText.cs │ │ │ ├── ButtonText.cs.meta │ │ │ ├── ButtonUI.cs │ │ │ ├── ButtonUI.cs.meta │ │ │ ├── ButtonUI_TMP.cs │ │ │ ├── ButtonUI_TMP.cs.meta │ │ │ ├── ButtonUI_Text.cs │ │ │ ├── ButtonUI_Text.cs.meta │ │ │ ├── Virtuesky.Sunflower.Button.asmdef │ │ │ └── Virtuesky.Sunflower.Button.asmdef.meta │ │ └── Runtime.meta │ ├── Button.meta │ ├── Component/ │ │ ├── AnimancerComponent/ │ │ │ ├── HandleAnimancerComponent.cs │ │ │ └── HandleAnimancerComponent.cs.meta │ │ ├── AnimancerComponent.meta │ │ ├── BounceComponent.cs │ │ ├── BounceComponent.cs.meta │ │ ├── Buoyancy2DComponent.cs │ │ ├── Buoyancy2DComponent.cs.meta │ │ ├── BuoyancyComponent.cs │ │ ├── BuoyancyComponent.cs.meta │ │ ├── EffectAppearComponent.cs │ │ ├── EffectAppearComponent.cs.meta │ │ ├── EffectZoomInOutComponent.cs │ │ ├── EffectZoomInOutComponent.cs.meta │ │ ├── FollowTargetComponent.cs │ │ ├── FollowTargetComponent.cs.meta │ │ ├── MoveComponent.cs │ │ ├── MoveComponent.cs.meta │ │ ├── ResizeCameraOrthographicComponent.cs │ │ ├── ResizeCameraOrthographicComponent.cs.meta │ │ ├── ResizeMatchCanvasScalerComponent.cs │ │ ├── ResizeMatchCanvasScalerComponent.cs.meta │ │ ├── RotateComponent.cs │ │ ├── RotateComponent.cs.meta │ │ ├── SafeAreaComponent.cs │ │ ├── SafeAreaComponent.cs.meta │ │ ├── SkeletonComponent/ │ │ │ ├── AnimationSkeleton/ │ │ │ │ ├── AnimationSkeleton.cs │ │ │ │ ├── AnimationSkeleton.cs.meta │ │ │ │ ├── AnimationSkeletonComponent.cs │ │ │ │ ├── AnimationSkeletonComponent.cs.meta │ │ │ │ ├── AnimationSkeletonUIComponent.cs │ │ │ │ └── AnimationSkeletonUIComponent.cs.meta │ │ │ ├── AnimationSkeleton.meta │ │ │ ├── SkinSkeleton/ │ │ │ │ ├── SkinSkeleton.cs │ │ │ │ ├── SkinSkeleton.cs.meta │ │ │ │ ├── SkinSkeletonComponent.cs │ │ │ │ ├── SkinSkeletonComponent.cs.meta │ │ │ │ ├── SkinSkeletonUIComponent.cs │ │ │ │ └── SkinSkeletonUIComponent.cs.meta │ │ │ └── SkinSkeleton.meta │ │ ├── SkeletonComponent.meta │ │ ├── TimeRemainingComponent.cs │ │ ├── TimeRemainingComponent.cs.meta │ │ ├── virtuesky.sunflower.component.asmdef │ │ └── virtuesky.sunflower.component.asmdef.meta │ ├── Component.meta │ ├── ControlPanel/ │ │ ├── CPAboutDrawer.cs │ │ ├── CPAboutDrawer.cs.meta │ │ ├── CPAdjustDrawer.cs │ │ ├── CPAdjustDrawer.cs.meta │ │ ├── CPAdvertisingDrawer.cs │ │ ├── CPAdvertisingDrawer.cs.meta │ │ ├── CPAppsFlyerDrawer.cs │ │ ├── CPAppsFlyerDrawer.cs.meta │ │ ├── CPAssetFinderDrawer.cs │ │ ├── CPAssetFinderDrawer.cs.meta │ │ ├── CPAudioDrawer.cs │ │ ├── CPAudioDrawer.cs.meta │ │ ├── CPExtensionsDrawer.cs │ │ ├── CPExtensionsDrawer.cs.meta │ │ ├── CPFirebaseDrawer.cs │ │ ├── CPFirebaseDrawer.cs.meta │ │ ├── CPFolderIconDrawer.cs │ │ ├── CPFolderIconDrawer.cs.meta │ │ ├── CPGameServiceDrawer.cs │ │ ├── CPGameServiceDrawer.cs.meta │ │ ├── CPHierarchyDrawer.cs │ │ ├── CPHierarchyDrawer.cs.meta │ │ ├── CPIapDrawer.cs │ │ ├── CPIapDrawer.cs.meta │ │ ├── CPInAppReviewDrawer.cs │ │ ├── CPInAppReviewDrawer.cs.meta │ │ ├── CPLevelEditorDrawer.cs │ │ ├── CPLevelEditorDrawer.cs.meta │ │ ├── CPLocalizationDrawer.cs │ │ ├── CPLocalizationDrawer.cs.meta │ │ ├── CPNotificationChanelDrawer.cs │ │ ├── CPNotificationChanelDrawer.cs.meta │ │ ├── CPRegisterPackageDrawer.cs │ │ ├── CPRegisterPackageDrawer.cs.meta │ │ ├── CPScriptingDefineSymbolsDrawer.cs │ │ ├── CPScriptingDefineSymbolsDrawer.cs.meta │ │ ├── CPSoEventDrawer.cs │ │ ├── CPSoEventDrawer.cs.meta │ │ ├── CPSoVariableDrawer.cs │ │ ├── CPSoVariableDrawer.cs.meta │ │ ├── CPUtility.cs │ │ ├── CPUtility.cs.meta │ │ ├── ConstantControlPanel.cs │ │ ├── ConstantControlPanel.cs.meta │ │ ├── ConstantPackage.cs │ │ ├── ConstantPackage.cs.meta │ │ ├── ControlPanelWindowEditor.cs │ │ ├── ControlPanelWindowEditor.cs.meta │ │ ├── Virtuesky.Sunflower.ControlPanel.Editor.asmdef │ │ └── Virtuesky.Sunflower.ControlPanel.Editor.asmdef.meta │ ├── ControlPanel.meta │ ├── Core/ │ │ ├── Editor/ │ │ │ ├── OptionalPropertyDrawer.cs │ │ │ ├── OptionalPropertyDrawer.cs.meta │ │ │ ├── VirtueSky.Sunflower.Core.Editor.asmdef │ │ │ └── VirtueSky.Sunflower.Core.Editor.asmdef.meta │ │ ├── Editor.meta │ │ ├── Runtime/ │ │ │ ├── App.cs │ │ │ ├── App.cs.meta │ │ │ ├── BaseMono.cs │ │ │ ├── BaseMono.cs.meta │ │ │ ├── BaseSO.cs │ │ │ ├── BaseSO.cs.meta │ │ │ ├── CacheComponent.cs │ │ │ ├── CacheComponent.cs.meta │ │ │ ├── DelayHandle.cs │ │ │ ├── DelayHandle.cs.meta │ │ │ ├── IEntity.cs │ │ │ ├── IEntity.cs.meta │ │ │ ├── MonoGlobal.cs │ │ │ ├── MonoGlobal.cs.meta │ │ │ ├── Optional.cs │ │ │ ├── Optional.cs.meta │ │ │ ├── RuntimeInitialize.cs │ │ │ ├── RuntimeInitialize.cs.meta │ │ │ ├── UnityServiceInitialization.cs │ │ │ ├── UnityServiceInitialization.cs.meta │ │ │ ├── virtuesky.sunflower.core.asmdef │ │ │ └── virtuesky.sunflower.core.asmdef.meta │ │ └── Runtime.meta │ ├── Core.meta │ ├── DataStorage/ │ │ ├── Editor/ │ │ │ ├── DataWindowEditor.cs │ │ │ ├── DataWindowEditor.cs.meta │ │ │ ├── Virtuesky.Sunflower.DataStorage.Editor.asmdef │ │ │ └── Virtuesky.Sunflower.DataStorage.Editor.asmdef.meta │ │ ├── Editor.meta │ │ ├── Runtime/ │ │ │ ├── GameData.cs │ │ │ ├── GameData.cs.meta │ │ │ ├── SerializeAdapter.cs │ │ │ ├── SerializeAdapter.cs.meta │ │ │ ├── Virtuesky.Sunflower.DataStorage.asmdef │ │ │ └── Virtuesky.Sunflower.DataStorage.asmdef.meta │ │ └── Runtime.meta │ ├── DataStorage.meta │ ├── DataType/ │ │ ├── DictionaryCustom.cs │ │ ├── DictionaryCustom.cs.meta │ │ ├── ShortDouble.Units.cs │ │ ├── ShortDouble.Units.cs.meta │ │ ├── ShortDouble.cs │ │ ├── ShortDouble.cs.meta │ │ ├── virtuesky.sunflower.datatype.asmdef │ │ └── virtuesky.sunflower.datatype.asmdef.meta │ ├── DataType.meta │ ├── Events/ │ │ ├── Editor/ │ │ │ ├── BaseEventEditor.cs │ │ │ ├── BaseEventEditor.cs.meta │ │ │ ├── EventWindowEditor.cs │ │ │ ├── EventWindowEditor.cs.meta │ │ │ ├── virtuesky.sunflower.event.editor.asmdef │ │ │ └── virtuesky.sunflower.event.editor.asmdef.meta │ │ ├── Editor.meta │ │ ├── Runtime/ │ │ │ ├── Base_Event/ │ │ │ │ ├── BaseEvent.cs │ │ │ │ ├── BaseEvent.cs.meta │ │ │ │ ├── BaseEventListener.cs │ │ │ │ ├── BaseEventListener.cs.meta │ │ │ │ ├── BaseEventResponse.cs │ │ │ │ ├── BaseEventResponse.cs.meta │ │ │ │ ├── EventListenerMono.cs │ │ │ │ └── EventListenerMono.cs.meta │ │ │ ├── Base_Event.meta │ │ │ ├── Boolean_Event/ │ │ │ │ ├── BooleanEvent.cs │ │ │ │ ├── BooleanEvent.cs.meta │ │ │ │ ├── BooleanEventListener.cs │ │ │ │ ├── BooleanEventListener.cs.meta │ │ │ │ ├── BooleanEventResponse.cs │ │ │ │ ├── BooleanEventResponse.cs.meta │ │ │ │ ├── Event_Result/ │ │ │ │ │ ├── BoolEventBoolResult.cs │ │ │ │ │ ├── BoolEventBoolResult.cs.meta │ │ │ │ │ ├── BoolEventFloatResult.cs │ │ │ │ │ ├── BoolEventFloatResult.cs.meta │ │ │ │ │ ├── BoolEventGameObjectResult.cs │ │ │ │ │ ├── BoolEventGameObjectResult.cs.meta │ │ │ │ │ ├── BoolEventIntResult.cs │ │ │ │ │ ├── BoolEventIntResult.cs.meta │ │ │ │ │ ├── BoolEventObjectResult.cs │ │ │ │ │ ├── BoolEventObjectResult.cs.meta │ │ │ │ │ ├── BoolEventStringResult.cs │ │ │ │ │ ├── BoolEventStringResult.cs.meta │ │ │ │ │ ├── BoolEventTransformResult.cs │ │ │ │ │ ├── BoolEventTransformResult.cs.meta │ │ │ │ │ ├── BoolEventVector3Result.cs │ │ │ │ │ └── BoolEventVector3Result.cs.meta │ │ │ │ └── Event_Result.meta │ │ │ ├── Boolean_Event.meta │ │ │ ├── Custom/ │ │ │ │ ├── ClickButtonEvent.cs │ │ │ │ └── ClickButtonEvent.cs.meta │ │ │ ├── Custom.meta │ │ │ ├── Dictionary_Event/ │ │ │ │ ├── DictionaryEvent.cs │ │ │ │ ├── DictionaryEvent.cs.meta │ │ │ │ ├── DictionaryEventListener.cs │ │ │ │ ├── DictionaryEventListener.cs.meta │ │ │ │ ├── DictionaryEventResponse.cs │ │ │ │ └── DictionaryEventResponse.cs.meta │ │ │ ├── Dictionary_Event.meta │ │ │ ├── Event_NoParam/ │ │ │ │ ├── EventListenerNoParam.cs │ │ │ │ ├── EventListenerNoParam.cs.meta │ │ │ │ ├── EventNoParam.cs │ │ │ │ ├── EventNoParam.cs.meta │ │ │ │ ├── EventResponse.cs │ │ │ │ ├── EventResponse.cs.meta │ │ │ │ ├── Event_Result/ │ │ │ │ │ ├── EventNoParamBoolResult.cs │ │ │ │ │ ├── EventNoParamBoolResult.cs.meta │ │ │ │ │ ├── EventNoParamFloatResult.cs │ │ │ │ │ ├── EventNoParamFloatResult.cs.meta │ │ │ │ │ ├── EventNoParamGameObjectResult.cs │ │ │ │ │ ├── EventNoParamGameObjectResult.cs.meta │ │ │ │ │ ├── EventNoParamIntResult.cs │ │ │ │ │ ├── EventNoParamIntResult.cs.meta │ │ │ │ │ ├── EventNoParamObjectResult.cs │ │ │ │ │ ├── EventNoParamObjectResult.cs.meta │ │ │ │ │ ├── EventNoParamResult.cs │ │ │ │ │ ├── EventNoParamResult.cs.meta │ │ │ │ │ ├── EventNoParamStringResult.cs │ │ │ │ │ ├── EventNoParamStringResult.cs.meta │ │ │ │ │ ├── EventNoParamTransformResult.cs │ │ │ │ │ ├── EventNoParamTransformResult.cs.meta │ │ │ │ │ ├── EventNoParamVector3Result.cs │ │ │ │ │ └── EventNoParamVector3Result.cs.meta │ │ │ │ └── Event_Result.meta │ │ │ ├── Event_NoParam.meta │ │ │ ├── Float_Event/ │ │ │ │ ├── Event_Result/ │ │ │ │ │ ├── FloatEventBoolResult.cs │ │ │ │ │ ├── FloatEventBoolResult.cs.meta │ │ │ │ │ ├── FloatEventFloatResult.cs │ │ │ │ │ ├── FloatEventFloatResult.cs.meta │ │ │ │ │ ├── FloatEventGameObjectResult.cs │ │ │ │ │ ├── FloatEventGameObjectResult.cs.meta │ │ │ │ │ ├── FloatEventIntResult.cs │ │ │ │ │ ├── FloatEventIntResult.cs.meta │ │ │ │ │ ├── FloatEventObjectResult.cs │ │ │ │ │ ├── FloatEventObjectResult.cs.meta │ │ │ │ │ ├── FloatEventStringResult.cs │ │ │ │ │ ├── FloatEventStringResult.cs.meta │ │ │ │ │ ├── FloatEventTransformResult.cs │ │ │ │ │ ├── FloatEventTransformResult.cs.meta │ │ │ │ │ ├── FloatEventVector3Result.cs │ │ │ │ │ └── FloatEventVector3Result.cs.meta │ │ │ │ ├── Event_Result.meta │ │ │ │ ├── FloatEvent.cs │ │ │ │ ├── FloatEvent.cs.meta │ │ │ │ ├── FloatEventListener.cs │ │ │ │ ├── FloatEventListener.cs.meta │ │ │ │ ├── FloatEventResponse.cs │ │ │ │ └── FloatEventResponse.cs.meta │ │ │ ├── Float_Event.meta │ │ │ ├── GameObject_Event/ │ │ │ │ ├── Event_Result/ │ │ │ │ │ ├── GameObjectEventBoolResult.cs │ │ │ │ │ ├── GameObjectEventBoolResult.cs.meta │ │ │ │ │ ├── GameObjectEventFloatResult.cs │ │ │ │ │ ├── GameObjectEventFloatResult.cs.meta │ │ │ │ │ ├── GameObjectEventGameObjectResult.cs │ │ │ │ │ ├── GameObjectEventGameObjectResult.cs.meta │ │ │ │ │ ├── GameObjectEventIntResult.cs │ │ │ │ │ ├── GameObjectEventIntResult.cs.meta │ │ │ │ │ ├── GameObjectEventObjectResult.cs │ │ │ │ │ ├── GameObjectEventObjectResult.cs.meta │ │ │ │ │ ├── GameObjectEventStringResult.cs │ │ │ │ │ ├── GameObjectEventStringResult.cs.meta │ │ │ │ │ ├── GameObjectEventTransformResult.cs │ │ │ │ │ ├── GameObjectEventTransformResult.cs.meta │ │ │ │ │ ├── GameObjectEventVector3Result.cs │ │ │ │ │ └── GameObjectEventVector3Result.cs.meta │ │ │ │ ├── Event_Result.meta │ │ │ │ ├── GameObjectEvent.cs │ │ │ │ ├── GameObjectEvent.cs.meta │ │ │ │ ├── GameObjectEventListener.cs │ │ │ │ ├── GameObjectEventListener.cs.meta │ │ │ │ ├── GameObjectEventResponse.cs │ │ │ │ └── GameObjectEventResponse.cs.meta │ │ │ ├── GameObject_Event.meta │ │ │ ├── Integer_Event/ │ │ │ │ ├── Event_Result/ │ │ │ │ │ ├── IntEventBoolResult.cs │ │ │ │ │ ├── IntEventBoolResult.cs.meta │ │ │ │ │ ├── IntEventFloatResult.cs │ │ │ │ │ ├── IntEventFloatResult.cs.meta │ │ │ │ │ ├── IntEventGameObjectResult.cs │ │ │ │ │ ├── IntEventGameObjectResult.cs.meta │ │ │ │ │ ├── IntEventIntResult.cs │ │ │ │ │ ├── IntEventIntResult.cs.meta │ │ │ │ │ ├── IntEventObjectResult.cs │ │ │ │ │ ├── IntEventObjectResult.cs.meta │ │ │ │ │ ├── IntEventStringResult.cs │ │ │ │ │ ├── IntEventStringResult.cs.meta │ │ │ │ │ ├── IntEventTransformResult.cs │ │ │ │ │ ├── IntEventTransformResult.cs.meta │ │ │ │ │ ├── IntEventVector3Result.cs │ │ │ │ │ └── IntEventVector3Result.cs.meta │ │ │ │ ├── Event_Result.meta │ │ │ │ ├── IntegerEvent.cs │ │ │ │ ├── IntegerEvent.cs.meta │ │ │ │ ├── IntegerEventListener.cs │ │ │ │ ├── IntegerEventListener.cs.meta │ │ │ │ ├── IntegerEventResponse.cs │ │ │ │ └── IntegerEventResponse.cs.meta │ │ │ ├── Integer_Event.meta │ │ │ ├── Interface_Event/ │ │ │ │ ├── IEvent.cs │ │ │ │ ├── IEvent.cs.meta │ │ │ │ ├── IEventListener.cs │ │ │ │ ├── IEventListener.cs.meta │ │ │ │ ├── IEventResponse.cs │ │ │ │ └── IEventResponse.cs.meta │ │ │ ├── Interface_Event.meta │ │ │ ├── Object_Event/ │ │ │ │ ├── Event_Result/ │ │ │ │ │ ├── ObjectEventBoolResult.cs │ │ │ │ │ ├── ObjectEventBoolResult.cs.meta │ │ │ │ │ ├── ObjectEventFloatResult.cs │ │ │ │ │ ├── ObjectEventFloatResult.cs.meta │ │ │ │ │ ├── ObjectEventGameObjectResult.cs │ │ │ │ │ ├── ObjectEventGameObjectResult.cs.meta │ │ │ │ │ ├── ObjectEventIntResult.cs │ │ │ │ │ ├── ObjectEventIntResult.cs.meta │ │ │ │ │ ├── ObjectEventObjectResult.cs │ │ │ │ │ ├── ObjectEventObjectResult.cs.meta │ │ │ │ │ ├── ObjectEventStringResult.cs │ │ │ │ │ ├── ObjectEventStringResult.cs.meta │ │ │ │ │ ├── ObjectEventTransformResult.cs │ │ │ │ │ ├── ObjectEventTransformResult.cs.meta │ │ │ │ │ ├── ObjectEventVector3Result.cs │ │ │ │ │ └── ObjectEventVector3Result.cs.meta │ │ │ │ ├── Event_Result.meta │ │ │ │ ├── ObjectEvent.cs │ │ │ │ ├── ObjectEvent.cs.meta │ │ │ │ ├── ObjectEventListener.cs │ │ │ │ ├── ObjectEventListener.cs.meta │ │ │ │ ├── ObjectEventResponse.cs │ │ │ │ └── ObjectEventResponse.cs.meta │ │ │ ├── Object_Event.meta │ │ │ ├── ShortDouble_Event/ │ │ │ │ ├── ShortDoubleEvent.cs │ │ │ │ ├── ShortDoubleEvent.cs.meta │ │ │ │ ├── ShortDoubleEventListener.cs │ │ │ │ ├── ShortDoubleEventListener.cs.meta │ │ │ │ ├── ShortDoubleEventResponse.cs │ │ │ │ └── ShortDoubleEventResponse.cs.meta │ │ │ ├── ShortDouble_Event.meta │ │ │ ├── String_Event/ │ │ │ │ ├── Event_Result/ │ │ │ │ │ ├── StringEventBoolResult.cs │ │ │ │ │ ├── StringEventBoolResult.cs.meta │ │ │ │ │ ├── StringEventFloatResult.cs │ │ │ │ │ ├── StringEventFloatResult.cs.meta │ │ │ │ │ ├── StringEventGameObjectResult.cs │ │ │ │ │ ├── StringEventGameObjectResult.cs.meta │ │ │ │ │ ├── StringEventIntResult.cs │ │ │ │ │ ├── StringEventIntResult.cs.meta │ │ │ │ │ ├── StringEventObjectResult.cs │ │ │ │ │ ├── StringEventObjectResult.cs.meta │ │ │ │ │ ├── StringEventStringResult.cs │ │ │ │ │ ├── StringEventStringResult.cs.meta │ │ │ │ │ ├── StringEventTransformResult.cs │ │ │ │ │ ├── StringEventTransformResult.cs.meta │ │ │ │ │ ├── StringEventVector3Result.cs │ │ │ │ │ └── StringEventVector3Result.cs.meta │ │ │ │ ├── Event_Result.meta │ │ │ │ ├── StringEvent.cs │ │ │ │ ├── StringEvent.cs.meta │ │ │ │ ├── StringEventListener.cs │ │ │ │ ├── StringEventListener.cs.meta │ │ │ │ ├── StringEventResponse.cs │ │ │ │ └── StringEventResponse.cs.meta │ │ │ ├── String_Event.meta │ │ │ ├── Transform_Event/ │ │ │ │ ├── Event_Result/ │ │ │ │ │ ├── TransformEventBoolResult.cs │ │ │ │ │ ├── TransformEventBoolResult.cs.meta │ │ │ │ │ ├── TransformEventFloatResult.cs │ │ │ │ │ ├── TransformEventFloatResult.cs.meta │ │ │ │ │ ├── TransformEventGameObjectResult.cs │ │ │ │ │ ├── TransformEventGameObjectResult.cs.meta │ │ │ │ │ ├── TransformEventIntResult.cs │ │ │ │ │ ├── TransformEventIntResult.cs.meta │ │ │ │ │ ├── TransformEventObjectResult.cs │ │ │ │ │ ├── TransformEventObjectResult.cs.meta │ │ │ │ │ ├── TransformEventStringResult.cs │ │ │ │ │ ├── TransformEventStringResult.cs.meta │ │ │ │ │ ├── TransformEventTransformResult.cs │ │ │ │ │ ├── TransformEventTransformResult.cs.meta │ │ │ │ │ ├── TransformEventVector3Result.cs │ │ │ │ │ └── TransformEventVector3Result.cs.meta │ │ │ │ ├── Event_Result.meta │ │ │ │ ├── TransformEvent.cs │ │ │ │ ├── TransformEvent.cs.meta │ │ │ │ ├── TransformEventListener.cs │ │ │ │ ├── TransformEventListener.cs.meta │ │ │ │ ├── TransformEventResponse.cs │ │ │ │ └── TransformEventResponse.cs.meta │ │ │ ├── Transform_Event.meta │ │ │ ├── Vector2_Event/ │ │ │ │ ├── Vector2Event.cs │ │ │ │ ├── Vector2Event.cs.meta │ │ │ │ ├── Vector2EventListener.cs │ │ │ │ ├── Vector2EventListener.cs.meta │ │ │ │ ├── Vector2EventResponse.cs │ │ │ │ └── Vector2EventResponse.cs.meta │ │ │ ├── Vector2_Event.meta │ │ │ ├── Vector3_Event/ │ │ │ │ ├── Event_Result/ │ │ │ │ │ ├── Vector3EventBoolResult.cs │ │ │ │ │ ├── Vector3EventBoolResult.cs.meta │ │ │ │ │ ├── Vector3EventFloatResult.cs │ │ │ │ │ ├── Vector3EventFloatResult.cs.meta │ │ │ │ │ ├── Vector3EventGameObjectResult.cs │ │ │ │ │ ├── Vector3EventGameObjectResult.cs.meta │ │ │ │ │ ├── Vector3EventIntResult.cs │ │ │ │ │ ├── Vector3EventIntResult.cs.meta │ │ │ │ │ ├── Vector3EventObjectResult.cs │ │ │ │ │ ├── Vector3EventObjectResult.cs.meta │ │ │ │ │ ├── Vector3EventStringResult.cs │ │ │ │ │ ├── Vector3EventStringResult.cs.meta │ │ │ │ │ ├── Vector3EventTransformResult.cs │ │ │ │ │ ├── Vector3EventTransformResult.cs.meta │ │ │ │ │ ├── Vector3EventVector3Result.cs │ │ │ │ │ └── Vector3EventVector3Result.cs.meta │ │ │ │ ├── Event_Result.meta │ │ │ │ ├── Vector3Event.cs │ │ │ │ ├── Vector3Event.cs.meta │ │ │ │ ├── Vector3EventListener.cs │ │ │ │ ├── Vector3EventListener.cs.meta │ │ │ │ ├── Vector3EventResponse.cs │ │ │ │ └── Vector3EventResponse.cs.meta │ │ │ ├── Vector3_Event.meta │ │ │ ├── virtuesky.sunflower.event.asmdef │ │ │ └── virtuesky.sunflower.event.asmdef.meta │ │ └── Runtime.meta │ ├── Events.meta │ ├── FolderIcon/ │ │ ├── Editor/ │ │ │ ├── CustomFolder.cs │ │ │ ├── CustomFolder.cs.meta │ │ │ ├── FolderIconSettings.cs │ │ │ ├── FolderIconSettings.cs.meta │ │ │ ├── IconDictionaryCreator.cs │ │ │ ├── IconDictionaryCreator.cs.meta │ │ │ ├── PackageIcon/ │ │ │ │ ├── icon_folder.unitypackage │ │ │ │ └── icon_folder.unitypackage.meta │ │ │ ├── PackageIcon.meta │ │ │ ├── Virtuesky.Sunflower.FolderIcon.asmdef │ │ │ └── Virtuesky.Sunflower.FolderIcon.asmdef.meta │ │ ├── Editor.meta │ │ ├── Icons/ │ │ │ ├── Animations.png.meta │ │ │ ├── Audio.png.meta │ │ │ ├── Default/ │ │ │ │ └── Default.png.meta │ │ │ ├── Default.meta │ │ │ ├── Editor.png.meta │ │ │ ├── Fonts.png.meta │ │ │ ├── Materials.png.meta │ │ │ ├── Models.png.meta │ │ │ ├── Plugins.png.meta │ │ │ ├── Prefabs.png.meta │ │ │ ├── Presets.png.meta │ │ │ ├── Resources.png.meta │ │ │ ├── Scenes.png.meta │ │ │ ├── Scripts.png.meta │ │ │ ├── Settings.png.meta │ │ │ ├── Shaders.png.meta │ │ │ ├── Sprites.png.meta │ │ │ └── Textures.png.meta │ │ └── Icons.meta │ ├── FolderIcon.meta │ ├── GameService/ │ │ ├── Runtime/ │ │ │ ├── AppleAuthentication.cs │ │ │ ├── AppleAuthentication.cs.meta │ │ │ ├── GooglePlayGamesAuthentication.cs │ │ │ ├── GooglePlayGamesAuthentication.cs.meta │ │ │ ├── ServiceAuthentication.cs │ │ │ ├── ServiceAuthentication.cs.meta │ │ │ ├── Variable/ │ │ │ │ ├── StatusLoginVariable.cs │ │ │ │ └── StatusLoginVariable.cs.meta │ │ │ ├── Variable.meta │ │ │ ├── Virtuesky.Sunflower.GameService.asmdef │ │ │ └── Virtuesky.Sunflower.GameService.asmdef.meta │ │ └── Runtime.meta │ ├── GameService.meta │ ├── Hierarchy/ │ │ ├── Attribute/ │ │ │ ├── HierarchyNullable.asmdef │ │ │ ├── HierarchyNullable.asmdef.meta │ │ │ ├── HierarchyNullable.cs │ │ │ └── HierarchyNullable.cs.meta │ │ ├── Attribute.meta │ │ ├── Editor/ │ │ │ ├── HierarchyEditor.asmdef │ │ │ ├── HierarchyEditor.asmdef.meta │ │ │ ├── Scripts/ │ │ │ │ ├── Component/ │ │ │ │ │ ├── Base/ │ │ │ │ │ │ ├── BaseComponent.cs │ │ │ │ │ │ └── BaseComponent.cs.meta │ │ │ │ │ ├── Base.meta │ │ │ │ │ ├── ChildrenCountComponent.cs │ │ │ │ │ ├── ChildrenCountComponent.cs.meta │ │ │ │ │ ├── ColorComponent.cs │ │ │ │ │ ├── ColorComponent.cs.meta │ │ │ │ │ ├── ComponentsComponent.cs │ │ │ │ │ ├── ComponentsComponent.cs.meta │ │ │ │ │ ├── ErrorComponent.cs │ │ │ │ │ ├── ErrorComponent.cs.meta │ │ │ │ │ ├── GameObjectIconComponent.cs │ │ │ │ │ ├── GameObjectIconComponent.cs.meta │ │ │ │ │ ├── LayerIconComponent.cs │ │ │ │ │ ├── LayerIconComponent.cs.meta │ │ │ │ │ ├── LockComponent.cs │ │ │ │ │ ├── LockComponent.cs.meta │ │ │ │ │ ├── MonoBehaviorIconComponent.cs │ │ │ │ │ ├── MonoBehaviorIconComponent.cs.meta │ │ │ │ │ ├── PrefabComponent.cs │ │ │ │ │ ├── PrefabComponent.cs.meta │ │ │ │ │ ├── RendererComponent.cs │ │ │ │ │ ├── RendererComponent.cs.meta │ │ │ │ │ ├── SeparatorComponent.cs │ │ │ │ │ ├── SeparatorComponent.cs.meta │ │ │ │ │ ├── StaticComponent.cs │ │ │ │ │ ├── StaticComponent.cs.meta │ │ │ │ │ ├── TagIconComponent.cs │ │ │ │ │ ├── TagIconComponent.cs.meta │ │ │ │ │ ├── TagLayerComponent.cs │ │ │ │ │ ├── TagLayerComponent.cs.meta │ │ │ │ │ ├── TreeMapComponent.cs │ │ │ │ │ ├── TreeMapComponent.cs.meta │ │ │ │ │ ├── VerticesAndTrianglesCountComponent.cs │ │ │ │ │ ├── VerticesAndTrianglesCountComponent.cs.meta │ │ │ │ │ ├── VisibilityComponent.cs │ │ │ │ │ └── VisibilityComponent.cs.meta │ │ │ │ ├── Component.meta │ │ │ │ ├── Data/ │ │ │ │ │ ├── HierarchyResources.cs │ │ │ │ │ ├── HierarchyResources.cs.meta │ │ │ │ │ ├── HierarchySettings.cs │ │ │ │ │ ├── HierarchySettings.cs.meta │ │ │ │ │ ├── HierarchySettingsObject.cs │ │ │ │ │ ├── HierarchySettingsObject.cs.meta │ │ │ │ │ ├── QSettingsObjectAsset.asset │ │ │ │ │ └── QSettingsObjectAsset.asset.meta │ │ │ │ ├── Data.meta │ │ │ │ ├── Helper/ │ │ │ │ │ ├── HierarchyColorPickerWindow.cs │ │ │ │ │ ├── HierarchyColorPickerWindow.cs.meta │ │ │ │ │ ├── HierarchyColorUtils.cs │ │ │ │ │ ├── HierarchyColorUtils.cs.meta │ │ │ │ │ ├── HierarchyComponentsOrderList.cs │ │ │ │ │ ├── HierarchyComponentsOrderList.cs.meta │ │ │ │ │ ├── HierarchyObjectListInspector.cs │ │ │ │ │ ├── HierarchyObjectListInspector.cs.meta │ │ │ │ │ ├── HierarchyObjectListManager.cs │ │ │ │ │ └── HierarchyObjectListManager.cs.meta │ │ │ │ ├── Helper.meta │ │ │ │ ├── QHierarchyInitializer.cs │ │ │ │ ├── QHierarchyInitializer.cs.meta │ │ │ │ ├── VHierarchy/ │ │ │ │ │ ├── HierarchySettingsWindow.cs │ │ │ │ │ ├── HierarchySettingsWindow.cs.meta │ │ │ │ │ ├── VHierarchy.cs │ │ │ │ │ └── VHierarchy.cs.meta │ │ │ │ └── VHierarchy.meta │ │ │ └── Scripts.meta │ │ ├── Editor.meta │ │ ├── FolderHierarchy/ │ │ │ ├── HeaderHierarchy.cs │ │ │ ├── HeaderHierarchy.cs.meta │ │ │ ├── HeaderHierarchyIcon.cs │ │ │ ├── HeaderHierarchyIcon.cs.meta │ │ │ ├── HierarchyHeader.asmdef │ │ │ ├── HierarchyHeader.asmdef.meta │ │ │ ├── InspectorUtility.cs │ │ │ └── InspectorUtility.cs.meta │ │ ├── FolderHierarchy.meta │ │ ├── Icons/ │ │ │ └── HierarchyHighlight.png.meta │ │ ├── Icons.meta │ │ ├── Scripts/ │ │ │ ├── HierarchyRuntime.asmdef │ │ │ ├── HierarchyRuntime.asmdef.meta │ │ │ ├── ObjectList.cs │ │ │ └── ObjectList.cs.meta │ │ └── Scripts.meta │ ├── Hierarchy.meta │ ├── Iap/ │ │ ├── Editor/ │ │ │ ├── IapSettingEditor.cs │ │ │ ├── IapSettingEditor.cs.meta │ │ │ ├── ObfuscationGenerator.cs │ │ │ ├── ObfuscationGenerator.cs.meta │ │ │ ├── TangleFileConsts.cs │ │ │ ├── TangleFileConsts.cs.meta │ │ │ ├── TangleObfuscator.cs │ │ │ ├── TangleObfuscator.cs.meta │ │ │ ├── Virtusky.Sunflower.Iap.Editor.asmdef │ │ │ └── Virtusky.Sunflower.Iap.Editor.asmdef.meta │ │ ├── Editor.meta │ │ ├── Runtime/ │ │ │ ├── IapDataVariable.cs │ │ │ ├── IapDataVariable.cs.meta │ │ │ ├── IapManager.cs │ │ │ ├── IapManager.cs.meta │ │ │ ├── IapPurchaseFailed.cs │ │ │ ├── IapPurchaseFailed.cs.meta │ │ │ ├── IapPurchaseSuccess.cs │ │ │ ├── IapPurchaseSuccess.cs.meta │ │ │ ├── IapSetting.cs │ │ │ ├── IapSetting.cs.meta │ │ │ ├── IapStatic.cs │ │ │ ├── IapStatic.cs.meta │ │ │ ├── Virtusky.Sunflower.Iap.asmdef │ │ │ └── Virtusky.Sunflower.Iap.asmdef.meta │ │ └── Runtime.meta │ ├── Iap.meta │ ├── Inspector/ │ │ ├── .editorconfig │ │ ├── .github/ │ │ │ ├── ISSUE_TEMPLATE/ │ │ │ │ ├── bug_report.md │ │ │ │ └── config.yml │ │ │ └── release.yml │ │ ├── .gitignore │ │ ├── Editor/ │ │ │ ├── AssemblyInfo.cs │ │ │ ├── AssemblyInfo.cs.meta │ │ │ ├── Attributes.cs │ │ │ ├── Attributes.cs.meta │ │ │ ├── CustomizeDraw/ │ │ │ │ ├── EditorIconPostProcessor.cs │ │ │ │ ├── EditorIconPostProcessor.cs.meta │ │ │ │ ├── EnumAttribue/ │ │ │ │ │ ├── ExtendEnumDrawer.cs │ │ │ │ │ ├── ExtendEnumDrawer.cs.meta │ │ │ │ │ ├── SearchableEnumDrawer.cs │ │ │ │ │ ├── SearchableEnumDrawer.cs.meta │ │ │ │ │ ├── SearchablePopup.cs │ │ │ │ │ └── SearchablePopup.cs.meta │ │ │ │ ├── EnumAttribue.meta │ │ │ │ ├── HeaderLineDrawer.cs │ │ │ │ ├── HeaderLineDrawer.cs.meta │ │ │ │ ├── HelpDrawer.cs │ │ │ │ ├── HelpDrawer.cs.meta │ │ │ │ ├── HighlightDrawer.cs │ │ │ │ ├── HighlightDrawer.cs.meta │ │ │ │ ├── LayerAttributeDraw.cs │ │ │ │ ├── LayerAttributeDraw.cs.meta │ │ │ │ ├── TagAttributeDraw.cs │ │ │ │ ├── TagAttributeDraw.cs.meta │ │ │ │ ├── TitleColorAttributeDrawer.cs │ │ │ │ ├── TitleColorAttributeDrawer.cs.meta │ │ │ │ ├── UtilityDraw.cs │ │ │ │ └── UtilityDraw.cs.meta │ │ │ ├── CustomizeDraw.meta │ │ │ ├── Editors/ │ │ │ │ ├── TriEditor.cs │ │ │ │ ├── TriEditor.cs.meta │ │ │ │ ├── TriEditorCore.cs │ │ │ │ ├── TriEditorCore.cs.meta │ │ │ │ ├── TriMonoBehaviourEditor.cs │ │ │ │ ├── TriMonoBehaviourEditor.cs.meta │ │ │ │ ├── TriScriptableObjectEditor.cs │ │ │ │ ├── TriScriptableObjectEditor.cs.meta │ │ │ │ ├── TriScriptedImporterEditor.cs │ │ │ │ ├── TriScriptedImporterEditor.cs.meta │ │ │ │ ├── TriSettingsProvider.cs │ │ │ │ └── TriSettingsProvider.cs.meta │ │ │ ├── Editors.meta │ │ │ ├── Elements/ │ │ │ │ ├── InlineEditorElement.cs │ │ │ │ ├── InlineEditorElement.cs.meta │ │ │ │ ├── TriBoxGroupElement.cs │ │ │ │ ├── TriBoxGroupElement.cs.meta │ │ │ │ ├── TriBuiltInPropertyElement.cs │ │ │ │ ├── TriBuiltInPropertyElement.cs.meta │ │ │ │ ├── TriDropdownElement.cs │ │ │ │ ├── TriDropdownElement.cs.meta │ │ │ │ ├── TriFoldoutElement.cs │ │ │ │ ├── TriFoldoutElement.cs.meta │ │ │ │ ├── TriHeaderGroupBaseElement.cs │ │ │ │ ├── TriHeaderGroupBaseElement.cs.meta │ │ │ │ ├── TriHorizontalGroupElement.cs │ │ │ │ ├── TriHorizontalGroupElement.cs.meta │ │ │ │ ├── TriInfoBoxElement.cs │ │ │ │ ├── TriInfoBoxElement.cs.meta │ │ │ │ ├── TriInlineGenericElement.cs │ │ │ │ ├── TriInlineGenericElement.cs.meta │ │ │ │ ├── TriLabelElement.cs │ │ │ │ ├── TriLabelElement.cs.meta │ │ │ │ ├── TriListElement.cs │ │ │ │ ├── TriListElement.cs.meta │ │ │ │ ├── TriMultiEditNotSupportedElement.cs │ │ │ │ ├── TriMultiEditNotSupportedElement.cs.meta │ │ │ │ ├── TriNoDrawerElement.cs │ │ │ │ ├── TriNoDrawerElement.cs.meta │ │ │ │ ├── TriPropertyCollectionBaseElement.cs │ │ │ │ ├── TriPropertyCollectionBaseElement.cs.meta │ │ │ │ ├── TriPropertyElement.cs │ │ │ │ ├── TriPropertyElement.cs.meta │ │ │ │ ├── TriReferenceElement.cs │ │ │ │ ├── TriReferenceElement.cs.meta │ │ │ │ ├── TriTabGroupElement.cs │ │ │ │ ├── TriTabGroupElement.cs.meta │ │ │ │ ├── TriUiToolkitPropertyElemenet.cs │ │ │ │ ├── TriUiToolkitPropertyElemenet.cs.meta │ │ │ │ ├── TriVerticalGroupElement.cs │ │ │ │ └── TriVerticalGroupElement.cs.meta │ │ │ ├── Elements.meta │ │ │ ├── Resolvers/ │ │ │ │ ├── ActionResolver.cs │ │ │ │ ├── ActionResolver.cs.meta │ │ │ │ ├── DropdownValuesResolver.cs │ │ │ │ ├── DropdownValuesResolver.cs.meta │ │ │ │ ├── ErrorActionResolver.cs │ │ │ │ ├── ErrorActionResolver.cs.meta │ │ │ │ ├── ErrorValueResolver.cs │ │ │ │ ├── ErrorValueResolver.cs.meta │ │ │ │ ├── InstanceActionResolver.cs │ │ │ │ ├── InstanceActionResolver.cs.meta │ │ │ │ ├── InstanceFieldValueResolver.cs │ │ │ │ ├── InstanceFieldValueResolver.cs.meta │ │ │ │ ├── InstanceMethodValueResolver.cs │ │ │ │ ├── InstanceMethodValueResolver.cs.meta │ │ │ │ ├── InstancePropertyValueResolver.cs │ │ │ │ ├── InstancePropertyValueResolver.cs.meta │ │ │ │ ├── StaticFieldValueResolver.cs │ │ │ │ ├── StaticFieldValueResolver.cs.meta │ │ │ │ ├── StaticMethodValueResolver.cs │ │ │ │ ├── StaticMethodValueResolver.cs.meta │ │ │ │ ├── StaticPropertyValueResolver.cs │ │ │ │ ├── StaticPropertyValueResolver.cs.meta │ │ │ │ ├── ValueResolver.cs │ │ │ │ └── ValueResolver.cs.meta │ │ │ ├── Resolvers.meta │ │ │ ├── Resources/ │ │ │ │ ├── TriInspector_Box_Bg.png.meta │ │ │ │ ├── TriInspector_Box_Bg_Dark.png.meta │ │ │ │ ├── TriInspector_Content_Bg.png.meta │ │ │ │ └── TriInspector_Content_Bg_Dark.png.meta │ │ │ ├── Resources.meta │ │ │ ├── TriAttributeDrawer.cs │ │ │ ├── TriAttributeDrawer.cs.meta │ │ │ ├── TriCustomDrawer.cs │ │ │ ├── TriCustomDrawer.cs.meta │ │ │ ├── TriDrawerOrder.cs │ │ │ ├── TriDrawerOrder.cs.meta │ │ │ ├── TriEditorStyles.cs │ │ │ ├── TriEditorStyles.cs.meta │ │ │ ├── TriElement.cs │ │ │ ├── TriElement.cs.meta │ │ │ ├── TriGroupDrawer.cs │ │ │ ├── TriGroupDrawer.cs.meta │ │ │ ├── TriProperty.cs │ │ │ ├── TriProperty.cs.meta │ │ │ ├── TriPropertyDefinition.cs │ │ │ ├── TriPropertyDefinition.cs.meta │ │ │ ├── TriPropertyDisableProcessor.cs │ │ │ ├── TriPropertyDisableProcessor.cs.meta │ │ │ ├── TriPropertyExtension.cs │ │ │ ├── TriPropertyExtension.cs.meta │ │ │ ├── TriPropertyHideProcessor.cs │ │ │ ├── TriPropertyHideProcessor.cs.meta │ │ │ ├── TriPropertyOverrideContext.cs │ │ │ ├── TriPropertyOverrideContext.cs.meta │ │ │ ├── TriPropertyTree.cs │ │ │ ├── TriPropertyTree.cs.meta │ │ │ ├── TriPropertyTreeForSerializedObject.cs │ │ │ ├── TriPropertyTreeForSerializedObject.cs.meta │ │ │ ├── TriTypeDefinition.cs │ │ │ ├── TriTypeDefinition.cs.meta │ │ │ ├── TriTypeProcessor.cs │ │ │ ├── TriTypeProcessor.cs.meta │ │ │ ├── TriValidator.cs │ │ │ ├── TriValidator.cs.meta │ │ │ ├── TriValue.cs │ │ │ ├── TriValue.cs.meta │ │ │ ├── TriValueDrawer.cs │ │ │ ├── TriValueDrawer.cs.meta │ │ │ ├── TypeProcessors/ │ │ │ │ ├── TriGroupNextTypeProcessor.cs │ │ │ │ ├── TriGroupNextTypeProcessor.cs.meta │ │ │ │ ├── TriRectOffsetTypeProcessor.cs │ │ │ │ ├── TriRectOffsetTypeProcessor.cs.meta │ │ │ │ ├── TriRegisterButtonsTypeProcessor.cs │ │ │ │ ├── TriRegisterButtonsTypeProcessor.cs.meta │ │ │ │ ├── TriRegisterShownByTriFieldsTypeProcessor.cs │ │ │ │ ├── TriRegisterShownByTriFieldsTypeProcessor.cs.meta │ │ │ │ ├── TriRegisterShownByTriPropertiesTypeProcessor.cs │ │ │ │ ├── TriRegisterShownByTriPropertiesTypeProcessor.cs.meta │ │ │ │ ├── TriRegisterUnitySerializedFieldsTypeProcessor.cs │ │ │ │ ├── TriRegisterUnitySerializedFieldsTypeProcessor.cs.meta │ │ │ │ ├── TriSortPropertiesTypeProcessor.cs │ │ │ │ └── TriSortPropertiesTypeProcessor.cs.meta │ │ │ ├── TypeProcessors.meta │ │ │ ├── Utilities/ │ │ │ │ ├── TriAttributeUtilities.cs │ │ │ │ ├── TriAttributeUtilities.cs.meta │ │ │ │ ├── TriDrawersUtilities.cs │ │ │ │ ├── TriDrawersUtilities.cs.meta │ │ │ │ ├── TriEditorGUI.cs │ │ │ │ ├── TriEditorGUI.cs.meta │ │ │ │ ├── TriEqualityComparer.cs │ │ │ │ ├── TriEqualityComparer.cs.meta │ │ │ │ ├── TriGuiHelper.cs │ │ │ │ ├── TriGuiHelper.cs.meta │ │ │ │ ├── TriManagedReferenceGui.cs │ │ │ │ ├── TriManagedReferenceGui.cs.meta │ │ │ │ ├── TriReflectionUtilities.cs │ │ │ │ ├── TriReflectionUtilities.cs.meta │ │ │ │ ├── TriTypeUtilities.cs │ │ │ │ ├── TriTypeUtilities.cs.meta │ │ │ │ ├── TriUnityInspectorUtilities.cs │ │ │ │ ├── TriUnityInspectorUtilities.cs.meta │ │ │ │ ├── TriUnitySerializationUtilities.cs │ │ │ │ └── TriUnitySerializationUtilities.cs.meta │ │ │ ├── Utilities.meta │ │ │ ├── ValidatorsDrawer.cs │ │ │ ├── ValidatorsDrawer.cs.meta │ │ │ ├── VirtueSky.Sunflower.Inspector.Editor.asmdef │ │ │ └── VirtueSky.Sunflower.Inspector.Editor.asmdef.meta │ │ ├── Editor.Extras/ │ │ │ ├── Drawers/ │ │ │ │ ├── BuiltinDrawerBase.cs │ │ │ │ ├── BuiltinDrawerBase.cs.meta │ │ │ │ ├── BuiltinDrawers.cs │ │ │ │ ├── BuiltinDrawers.cs.meta │ │ │ │ ├── ButtonDrawer.cs │ │ │ │ ├── ButtonDrawer.cs.meta │ │ │ │ ├── CustomBuiltInDrawer.cs │ │ │ │ ├── CustomBuiltInDrawer.cs.meta │ │ │ │ ├── DisplayAsStringDrawer.cs │ │ │ │ ├── DisplayAsStringDrawer.cs.meta │ │ │ │ ├── DropdownDrawer.cs │ │ │ │ ├── DropdownDrawer.cs.meta │ │ │ │ ├── EnumToggleButtonsDrawer.cs │ │ │ │ ├── EnumToggleButtonsDrawer.cs.meta │ │ │ │ ├── GUIColorDrawer.cs │ │ │ │ ├── GUIColorDrawer.cs.meta │ │ │ │ ├── IndentDrawer.cs │ │ │ │ ├── IndentDrawer.cs.meta │ │ │ │ ├── InlineEditorDrawer.cs │ │ │ │ ├── InlineEditorDrawer.cs.meta │ │ │ │ ├── LabelWidthDrawer.cs │ │ │ │ ├── LabelWidthDrawer.cs.meta │ │ │ │ ├── ObjectReferenceDrawer.cs │ │ │ │ ├── ObjectReferenceDrawer.cs.meta │ │ │ │ ├── OnValueChangedDrawer.cs │ │ │ │ ├── OnValueChangedDrawer.cs.meta │ │ │ │ ├── PreviewMeshDrawer.cs │ │ │ │ ├── PreviewMeshDrawer.cs.meta │ │ │ │ ├── PropertySpaceDrawer.cs │ │ │ │ ├── PropertySpaceDrawer.cs.meta │ │ │ │ ├── SceneDrawer.cs │ │ │ │ ├── SceneDrawer.cs.meta │ │ │ │ ├── ShowDrawerChainDrawer.cs │ │ │ │ ├── ShowDrawerChainDrawer.cs.meta │ │ │ │ ├── TableListDrawer.cs │ │ │ │ ├── TableListDrawer.cs.meta │ │ │ │ ├── TitleDrawer.cs │ │ │ │ ├── TitleDrawer.cs.meta │ │ │ │ ├── UnitDrawer.cs │ │ │ │ └── UnitDrawer.cs.meta │ │ │ ├── Drawers.meta │ │ │ ├── GroupDrawers/ │ │ │ │ ├── TriBoxGroupDrawer.cs │ │ │ │ ├── TriBoxGroupDrawer.cs.meta │ │ │ │ ├── TriFoldoutGroupDrawer.cs │ │ │ │ ├── TriFoldoutGroupDrawer.cs.meta │ │ │ │ ├── TriHorizontalGroupDrawer.cs │ │ │ │ ├── TriHorizontalGroupDrawer.cs.meta │ │ │ │ ├── TriTabGroupDrawer.cs │ │ │ │ ├── TriTabGroupDrawer.cs.meta │ │ │ │ ├── TriToggleGroupDrawer.cs │ │ │ │ ├── TriToggleGroupDrawer.cs.meta │ │ │ │ ├── TriVerticalGroupDrawer.cs │ │ │ │ └── TriVerticalGroupDrawer.cs.meta │ │ │ ├── GroupDrawers.meta │ │ │ ├── Processors/ │ │ │ │ ├── DisableIfProcessor.cs │ │ │ │ ├── DisableIfProcessor.cs.meta │ │ │ │ ├── DisableInEditModeProcessor.cs │ │ │ │ ├── DisableInEditModeProcessor.cs.meta │ │ │ │ ├── DisableInPlayModeProcessor.cs │ │ │ │ ├── DisableInPlayModeProcessor.cs.meta │ │ │ │ ├── HIdeInEditModeProcessor.cs │ │ │ │ ├── HIdeInEditModeProcessor.cs.meta │ │ │ │ ├── HideIfProcessor.cs │ │ │ │ ├── HideIfProcessor.cs.meta │ │ │ │ ├── HideInPlayModeProcessor.cs │ │ │ │ └── HideInPlayModeProcessor.cs.meta │ │ │ ├── Processors.meta │ │ │ ├── Validators/ │ │ │ │ ├── AssetsOnlyValidator.cs │ │ │ │ ├── AssetsOnlyValidator.cs.meta │ │ │ │ ├── DropdownValidator.cs │ │ │ │ ├── DropdownValidator.cs.meta │ │ │ │ ├── InfoBoxValidator.cs │ │ │ │ ├── InfoBoxValidator.cs.meta │ │ │ │ ├── MissingReferenceValidator.cs │ │ │ │ ├── MissingReferenceValidator.cs.meta │ │ │ │ ├── RequiredValidator.cs │ │ │ │ ├── RequiredValidator.cs.meta │ │ │ │ ├── SceneObjectsOnlyValidator.cs │ │ │ │ ├── SceneObjectsOnlyValidator.cs.meta │ │ │ │ ├── SceneValidator.cs │ │ │ │ ├── SceneValidator.cs.meta │ │ │ │ ├── TypeMismatchValidator.cs │ │ │ │ ├── TypeMismatchValidator.cs.meta │ │ │ │ ├── ValidateInputValidator.cs │ │ │ │ └── ValidateInputValidator.cs.meta │ │ │ ├── Validators.meta │ │ │ ├── VirtueSky.Sunflower.Inspector.Editor.Extras.asmdef │ │ │ └── VirtueSky.Sunflower.Inspector.Editor.Extras.asmdef.meta │ │ ├── Editor.Extras.meta │ │ ├── Editor.meta │ │ ├── Runtime/ │ │ │ ├── Attributes/ │ │ │ │ ├── Buttons/ │ │ │ │ │ ├── ButtonAttribute.cs │ │ │ │ │ ├── ButtonAttribute.cs.meta │ │ │ │ │ ├── EnumToggleButtonsAttribute.cs │ │ │ │ │ └── EnumToggleButtonsAttribute.cs.meta │ │ │ │ ├── Buttons.meta │ │ │ │ ├── Collections/ │ │ │ │ │ ├── ListDrawerSettings.cs │ │ │ │ │ ├── ListDrawerSettings.cs.meta │ │ │ │ │ ├── TableListAttribute.cs │ │ │ │ │ └── TableListAttribute.cs.meta │ │ │ │ ├── Collections.meta │ │ │ │ ├── Conditionals/ │ │ │ │ │ ├── DisableIfAttribute.cs │ │ │ │ │ ├── DisableIfAttribute.cs.meta │ │ │ │ │ ├── DisableInEditModeAttribute.cs │ │ │ │ │ ├── DisableInEditModeAttribute.cs.meta │ │ │ │ │ ├── DisableInPlayModeAttribute.cs │ │ │ │ │ ├── DisableInPlayModeAttribute.cs.meta │ │ │ │ │ ├── EnableIfAttribute.cs │ │ │ │ │ ├── EnableIfAttribute.cs.meta │ │ │ │ │ ├── EnableInEditModeAttribute.cs │ │ │ │ │ ├── EnableInEditModeAttribute.cs.meta │ │ │ │ │ ├── EnableInPlayModeAttribute.cs │ │ │ │ │ ├── EnableInPlayModeAttribute.cs.meta │ │ │ │ │ ├── HideIfAttribute.cs │ │ │ │ │ ├── HideIfAttribute.cs.meta │ │ │ │ │ ├── HideInEditModeAttribute.cs │ │ │ │ │ ├── HideInEditModeAttribute.cs.meta │ │ │ │ │ ├── HideInPlayModeAttribute.cs │ │ │ │ │ ├── HideInPlayModeAttribute.cs.meta │ │ │ │ │ ├── ShowIfAttribute.cs │ │ │ │ │ ├── ShowIfAttribute.cs.meta │ │ │ │ │ ├── ShowInEditModeAttribute.cs │ │ │ │ │ ├── ShowInEditModeAttribute.cs.meta │ │ │ │ │ ├── ShowInPlayModeAttribute.cs │ │ │ │ │ └── ShowInPlayModeAttribute.cs.meta │ │ │ │ ├── Conditionals.meta │ │ │ │ ├── Debug/ │ │ │ │ │ ├── ShowDrawerChainAttribute.cs │ │ │ │ │ └── ShowDrawerChainAttribute.cs.meta │ │ │ │ ├── Debug.meta │ │ │ │ ├── Decorators/ │ │ │ │ │ ├── DisplayAsStringAttribute.cs │ │ │ │ │ ├── DisplayAsStringAttribute.cs.meta │ │ │ │ │ ├── DropdownAttribute.cs │ │ │ │ │ ├── DropdownAttribute.cs.meta │ │ │ │ │ ├── InlineEditorAttribute.cs │ │ │ │ │ ├── InlineEditorAttribute.cs.meta │ │ │ │ │ ├── PreviewMeshAttribute.cs │ │ │ │ │ ├── PreviewMeshAttribute.cs.meta │ │ │ │ │ ├── SceneAttribute.cs │ │ │ │ │ ├── SceneAttribute.cs.meta │ │ │ │ │ ├── UnitAttribute.cs │ │ │ │ │ └── UnitAttribute.cs.meta │ │ │ │ ├── Decorators.meta │ │ │ │ ├── Groups/ │ │ │ │ │ ├── DeclareBoxGroupAttribute.cs │ │ │ │ │ ├── DeclareBoxGroupAttribute.cs.meta │ │ │ │ │ ├── DeclareFoldoutGroupAttribute.cs │ │ │ │ │ ├── DeclareFoldoutGroupAttribute.cs.meta │ │ │ │ │ ├── DeclareGroupBaseAttribute.cs │ │ │ │ │ ├── DeclareGroupBaseAttribute.cs.meta │ │ │ │ │ ├── DeclareHorizontalGroupAttribute.cs │ │ │ │ │ ├── DeclareHorizontalGroupAttribute.cs.meta │ │ │ │ │ ├── DeclareTabGroupAttribute.cs │ │ │ │ │ ├── DeclareTabGroupAttribute.cs.meta │ │ │ │ │ ├── DeclareToggleGroupAttribute.cs │ │ │ │ │ ├── DeclareToggleGroupAttribute.cs.meta │ │ │ │ │ ├── DeclareVerticalGroupAttribute.cs │ │ │ │ │ ├── DeclareVerticalGroupAttribute.cs.meta │ │ │ │ │ ├── GroupAttribute.cs │ │ │ │ │ ├── GroupAttribute.cs.meta │ │ │ │ │ ├── GroupNextAttribute.cs │ │ │ │ │ ├── GroupNextAttribute.cs.meta │ │ │ │ │ ├── TabAttribute.cs │ │ │ │ │ └── TabAttribute.cs.meta │ │ │ │ ├── Groups.meta │ │ │ │ ├── Misc/ │ │ │ │ │ ├── HideMonoScriptAttribute.cs │ │ │ │ │ ├── HideMonoScriptAttribute.cs.meta │ │ │ │ │ ├── HideReferencePickerAttribute.cs │ │ │ │ │ ├── HideReferencePickerAttribute.cs.meta │ │ │ │ │ ├── OnValueChangedAttribute.cs │ │ │ │ │ ├── OnValueChangedAttribute.cs.meta │ │ │ │ │ ├── PropertyOrderAttribute.cs │ │ │ │ │ ├── PropertyOrderAttribute.cs.meta │ │ │ │ │ ├── ReadOnlyAttribute.cs │ │ │ │ │ ├── ReadOnlyAttribute.cs.meta │ │ │ │ │ ├── ShowInInspector.cs │ │ │ │ │ └── ShowInInspector.cs.meta │ │ │ │ ├── Misc.meta │ │ │ │ ├── Others/ │ │ │ │ │ ├── DrawWithTriInspectorAttribute.cs │ │ │ │ │ ├── DrawWithTriInspectorAttribute.cs.meta │ │ │ │ │ ├── DrawWithUnityAttribute.cs │ │ │ │ │ └── DrawWithUnityAttribute.cs.meta │ │ │ │ ├── Others.meta │ │ │ │ ├── Styling/ │ │ │ │ │ ├── GUIColorAttribute.cs │ │ │ │ │ ├── GUIColorAttribute.cs.meta │ │ │ │ │ ├── HideLabelAttribute.cs │ │ │ │ │ ├── HideLabelAttribute.cs.meta │ │ │ │ │ ├── IndentAttribute.cs │ │ │ │ │ ├── IndentAttribute.cs.meta │ │ │ │ │ ├── InlinePropertyAttribute.cs │ │ │ │ │ ├── InlinePropertyAttribute.cs.meta │ │ │ │ │ ├── LabelTextAttribute.cs │ │ │ │ │ ├── LabelTextAttribute.cs.meta │ │ │ │ │ ├── LabelWidthAttribute.cs │ │ │ │ │ ├── LabelWidthAttribute.cs.meta │ │ │ │ │ ├── PropertySpaceAttribute.cs │ │ │ │ │ ├── PropertySpaceAttribute.cs.meta │ │ │ │ │ ├── PropertyTooltipAttribute.cs │ │ │ │ │ ├── PropertyTooltipAttribute.cs.meta │ │ │ │ │ ├── TitleAttribute.cs │ │ │ │ │ └── TitleAttribute.cs.meta │ │ │ │ ├── Styling.meta │ │ │ │ ├── Validators/ │ │ │ │ │ ├── AssetsOnlyAttribute.cs │ │ │ │ │ ├── AssetsOnlyAttribute.cs.meta │ │ │ │ │ ├── InfoBoxAttribute.cs │ │ │ │ │ ├── InfoBoxAttribute.cs.meta │ │ │ │ │ ├── RequiredAttribute.cs │ │ │ │ │ ├── RequiredAttribute.cs.meta │ │ │ │ │ ├── SceneObjectsOnlyAttribute.cs │ │ │ │ │ ├── SceneObjectsOnlyAttribute.cs.meta │ │ │ │ │ ├── ValidateInputAttribute.cs │ │ │ │ │ └── ValidateInputAttribute.cs.meta │ │ │ │ └── Validators.meta │ │ │ ├── Attributes.meta │ │ │ ├── ButtonSizes.cs │ │ │ ├── ButtonSizes.cs.meta │ │ │ ├── CustomizeAttribute/ │ │ │ │ ├── Attribute/ │ │ │ │ │ ├── EditorIconAttribute.cs │ │ │ │ │ ├── EditorIconAttribute.cs.meta │ │ │ │ │ ├── EnumAttribue/ │ │ │ │ │ │ ├── ExtendEnumAttribute.cs │ │ │ │ │ │ ├── ExtendEnumAttribute.cs.meta │ │ │ │ │ │ ├── SearchableEnumAttribute.cs │ │ │ │ │ │ └── SearchableEnumAttribute.cs.meta │ │ │ │ │ ├── EnumAttribue.meta │ │ │ │ │ ├── HeaderLineAttribute.cs │ │ │ │ │ ├── HeaderLineAttribute.cs.meta │ │ │ │ │ ├── HelpBoxAttribute.cs │ │ │ │ │ ├── HelpBoxAttribute.cs.meta │ │ │ │ │ ├── HighlightAttribute.cs │ │ │ │ │ ├── HighlightAttribute.cs.meta │ │ │ │ │ ├── LayerAttribute.cs │ │ │ │ │ ├── LayerAttribute.cs.meta │ │ │ │ │ ├── TagAttribute.cs │ │ │ │ │ ├── TagAttribute.cs.meta │ │ │ │ │ ├── TitleColorAttribute.cs │ │ │ │ │ └── TitleColorAttribute.cs.meta │ │ │ │ ├── Attribute.meta │ │ │ │ ├── GUIDAttribute.cs │ │ │ │ ├── GUIDAttribute.cs.meta │ │ │ │ ├── NamedIdAttribute.cs │ │ │ │ └── NamedIdAttribute.cs.meta │ │ │ ├── CustomizeAttribute.meta │ │ │ ├── InlineEditorModes.cs │ │ │ ├── InlineEditorModes.cs.meta │ │ │ ├── PreviewMeshRotationMethod.cs │ │ │ ├── PreviewMeshRotationMethod.cs.meta │ │ │ ├── TriDropdownList.cs │ │ │ ├── TriDropdownList.cs.meta │ │ │ ├── TriValidationResult.cs │ │ │ ├── TriValidationResult.cs.meta │ │ │ ├── VirtueSky.Sunflower.Inspector.asmdef │ │ │ └── VirtueSky.Sunflower.Inspector.asmdef.meta │ │ ├── Runtime.meta │ │ ├── Unity.InternalAPIEditorBridge.012/ │ │ │ ├── AdvancedDropdownProxy.cs │ │ │ ├── AdvancedDropdownProxy.cs.meta │ │ │ ├── AssemblyInfo.cs │ │ │ ├── AssemblyInfo.cs.meta │ │ │ ├── EditorGUIUtilityProxy.cs │ │ │ ├── EditorGUIUtilityProxy.cs.meta │ │ │ ├── EditorProxy.cs │ │ │ ├── EditorProxy.cs.meta │ │ │ ├── GUIClipProxy.cs │ │ │ ├── GUIClipProxy.cs.meta │ │ │ ├── InternalEditorUtilityProxy.cs │ │ │ ├── InternalEditorUtilityProxy.cs.meta │ │ │ ├── ReorderableListProxy.cs │ │ │ ├── ReorderableListProxy.cs.meta │ │ │ ├── ScriptAttributeUtilityProxy.cs │ │ │ ├── ScriptAttributeUtilityProxy.cs.meta │ │ │ ├── Unity.InternalAPIEditorBridge.013.asmdef │ │ │ └── Unity.InternalAPIEditorBridge.013.asmdef.meta │ │ ├── Unity.InternalAPIEditorBridge.012.meta │ │ ├── Version.txt │ │ └── Version.txt.meta │ ├── Inspector.meta │ ├── LevelEditor/ │ │ ├── LevelEditor.cs │ │ ├── LevelEditor.cs.meta │ │ ├── LevelSystemEditorSetting.cs │ │ ├── LevelSystemEditorSetting.cs.meta │ │ ├── PickObject.cs │ │ ├── PickObject.cs.meta │ │ ├── PreviewGenerator.cs │ │ ├── PreviewGenerator.cs.meta │ │ ├── Probe.cs │ │ ├── Probe.cs.meta │ │ ├── virtuesky.sunflower.leveleditor.asmdef │ │ └── virtuesky.sunflower.leveleditor.asmdef.meta │ ├── LevelEditor.meta │ ├── Linq/ │ │ ├── Aggregate.cs │ │ ├── Aggregate.cs.meta │ │ ├── AnyAll.cs │ │ ├── AnyAll.cs.meta │ │ ├── Average.cs │ │ ├── Average.cs.meta │ │ ├── Chunk.cs │ │ ├── Chunk.cs.meta │ │ ├── Contains.cs │ │ ├── Contains.cs.meta │ │ ├── Count.cs │ │ ├── Count.cs.meta │ │ ├── Distinct.cs │ │ ├── Distinct.cs.meta │ │ ├── First.cs │ │ ├── First.cs.meta │ │ ├── Flatten.cs │ │ ├── Flatten.cs.meta │ │ ├── Last.cs │ │ ├── Last.cs.meta │ │ ├── Max.cs │ │ ├── Max.cs.meta │ │ ├── Min.cs │ │ ├── Min.cs.meta │ │ ├── OrderBy.cs │ │ ├── OrderBy.cs.meta │ │ ├── Range.cs │ │ ├── Range.cs.meta │ │ ├── Repeat.cs │ │ ├── Repeat.cs.meta │ │ ├── Reverse.cs │ │ ├── Reverse.cs.meta │ │ ├── Select.cs │ │ ├── Select.cs.meta │ │ ├── SelectMany.cs │ │ ├── SelectMany.cs.meta │ │ ├── SelectWhere.cs │ │ ├── SelectWhere.cs.meta │ │ ├── SequenceEqual.cs │ │ ├── SequenceEqual.cs.meta │ │ ├── Single.cs │ │ ├── Single.cs.meta │ │ ├── Skip.cs │ │ ├── Skip.cs.meta │ │ ├── Sum.cs │ │ ├── Sum.cs.meta │ │ ├── Take.cs │ │ ├── Take.cs.meta │ │ ├── Utils/ │ │ │ ├── ComparerMagic.cs │ │ │ ├── ComparerMagic.cs.meta │ │ │ ├── CustomPartition.cs │ │ │ ├── CustomPartition.cs.meta │ │ │ ├── GenericOperators.cs │ │ │ ├── GenericOperators.cs.meta │ │ │ ├── SliceHelper.cs │ │ │ └── SliceHelper.cs.meta │ │ ├── Utils.meta │ │ ├── VirtueSky.Sunflower.Linq.asmdef │ │ ├── VirtueSky.Sunflower.Linq.asmdef.meta │ │ ├── Where.cs │ │ ├── Where.cs.meta │ │ ├── WhereAggregate.cs │ │ ├── WhereAggregate.cs.meta │ │ ├── WhereSelect.cs │ │ ├── WhereSelect.cs.meta │ │ ├── WhereSum.cs │ │ ├── WhereSum.cs.meta │ │ ├── Zip.cs │ │ └── Zip.cs.meta │ ├── Linq.meta │ ├── Localization/ │ │ ├── Editor/ │ │ │ ├── AssetTreeViewItem.cs │ │ │ ├── AssetTreeViewItem.cs.meta │ │ │ ├── CsvSerialization.cs │ │ │ ├── CsvSerialization.cs.meta │ │ │ ├── EditorMenu.cs │ │ │ ├── EditorMenu.cs.meta │ │ │ ├── LanguagePropertyDrawer.cs │ │ │ ├── LanguagePropertyDrawer.cs.meta │ │ │ ├── LocaleEditorUtil.cs │ │ │ ├── LocaleEditorUtil.cs.meta │ │ │ ├── LocaleSettingsEditor.cs │ │ │ ├── LocaleSettingsEditor.cs.meta │ │ │ ├── LocaleTreeView.cs │ │ │ ├── LocaleTreeView.cs.meta │ │ │ ├── LocaleTreeViewItem.cs │ │ │ ├── LocaleTreeViewItem.cs.meta │ │ │ ├── PostBuildProcessor.cs │ │ │ ├── PostBuildProcessor.cs.meta │ │ │ ├── ScriptableLocaleEditor.cs │ │ │ ├── ScriptableLocaleEditor.cs.meta │ │ │ ├── VirtueSky.Sunflower.Localization.Editor.asmdef │ │ │ └── VirtueSky.Sunflower.Localization.Editor.asmdef.meta │ │ ├── Editor.meta │ │ ├── Runtime/ │ │ │ ├── Implement/ │ │ │ │ ├── Behaviour/ │ │ │ │ │ ├── LocaleAudioClipComponent.cs │ │ │ │ │ ├── LocaleAudioClipComponent.cs.meta │ │ │ │ │ ├── LocaleComponent.cs │ │ │ │ │ ├── LocaleComponent.cs.meta │ │ │ │ │ ├── LocaleComponentGeneric.cs │ │ │ │ │ ├── LocaleComponentGeneric.cs.meta │ │ │ │ │ ├── LocaleComponentGenericBase.cs │ │ │ │ │ ├── LocaleComponentGenericBase.cs.meta │ │ │ │ │ ├── LocaleFontComponent.cs │ │ │ │ │ ├── LocaleFontComponent.cs.meta │ │ │ │ │ ├── LocaleMaterialComponent.cs │ │ │ │ │ ├── LocaleMaterialComponent.cs.meta │ │ │ │ │ ├── LocalePrefabComponent.cs │ │ │ │ │ ├── LocalePrefabComponent.cs.meta │ │ │ │ │ ├── LocaleRendererComponent.cs │ │ │ │ │ ├── LocaleRendererComponent.cs.meta │ │ │ │ │ ├── LocaleSharedMaterialComponent.cs │ │ │ │ │ ├── LocaleSharedMaterialComponent.cs.meta │ │ │ │ │ ├── LocaleSpriteComponent.cs │ │ │ │ │ ├── LocaleSpriteComponent.cs.meta │ │ │ │ │ ├── LocaleTMPFontComponent.cs │ │ │ │ │ ├── LocaleTMPFontComponent.cs.meta │ │ │ │ │ ├── LocaleTextAssetComponent.cs │ │ │ │ │ ├── LocaleTextAssetComponent.cs.meta │ │ │ │ │ ├── LocaleTextComponent.cs │ │ │ │ │ ├── LocaleTextComponent.cs.meta │ │ │ │ │ ├── LocaleTextCompositeComponent.cs │ │ │ │ │ ├── LocaleTextCompositeComponent.cs.meta │ │ │ │ │ ├── LocaleTextureComponent.cs │ │ │ │ │ ├── LocaleTextureComponent.cs.meta │ │ │ │ │ ├── LocaleTextureMaterialComponent.cs │ │ │ │ │ ├── LocaleTextureMaterialComponent.cs.meta │ │ │ │ │ ├── LocaleVideoClipComponent.cs │ │ │ │ │ └── LocaleVideoClipComponent.cs.meta │ │ │ │ ├── Behaviour.meta │ │ │ │ ├── Event/ │ │ │ │ │ ├── ScriptableEventLocaleText.cs │ │ │ │ │ └── ScriptableEventLocaleText.cs.meta │ │ │ │ ├── Event.meta │ │ │ │ ├── Variable/ │ │ │ │ │ ├── LocaleAudioClip.cs │ │ │ │ │ ├── LocaleAudioClip.cs.meta │ │ │ │ │ ├── LocaleFont.cs │ │ │ │ │ ├── LocaleFont.cs.meta │ │ │ │ │ ├── LocaleMaterial.cs │ │ │ │ │ ├── LocaleMaterial.cs.meta │ │ │ │ │ ├── LocalePrefab.cs │ │ │ │ │ ├── LocalePrefab.cs.meta │ │ │ │ │ ├── LocaleSprite.cs │ │ │ │ │ ├── LocaleSprite.cs.meta │ │ │ │ │ ├── LocaleTMPFont.cs │ │ │ │ │ ├── LocaleTMPFont.cs.meta │ │ │ │ │ ├── LocaleText.cs │ │ │ │ │ ├── LocaleText.cs.meta │ │ │ │ │ ├── LocaleTextAsset.cs │ │ │ │ │ ├── LocaleTextAsset.cs.meta │ │ │ │ │ ├── LocaleTexture.cs │ │ │ │ │ ├── LocaleTexture.cs.meta │ │ │ │ │ ├── LocaleVariable.cs │ │ │ │ │ ├── LocaleVariable.cs.meta │ │ │ │ │ ├── LocaleVideoClip.cs │ │ │ │ │ ├── LocaleVideoClip.cs.meta │ │ │ │ │ ├── ScriptableLocaleBase.cs │ │ │ │ │ └── ScriptableLocaleBase.cs.meta │ │ │ │ └── Variable.meta │ │ │ ├── Implement.meta │ │ │ ├── Language.cs │ │ │ ├── Language.cs.meta │ │ │ ├── Locale.cs │ │ │ ├── Locale.cs.meta │ │ │ ├── LocaleChangedEventArgs.cs │ │ │ ├── LocaleChangedEventArgs.cs.meta │ │ │ ├── LocaleItem.cs │ │ │ ├── LocaleItem.cs.meta │ │ │ ├── LocaleItemBase.cs │ │ │ ├── LocaleItemBase.cs.meta │ │ │ ├── LocaleSettings.cs │ │ │ ├── LocaleSettings.cs.meta │ │ │ ├── Translate/ │ │ │ │ ├── GoogleTranslateRequest.cs │ │ │ │ ├── GoogleTranslateRequest.cs.meta │ │ │ │ ├── GoogleTranslateResponse.cs │ │ │ │ ├── GoogleTranslateResponse.cs.meta │ │ │ │ ├── GoogleTranslator.cs │ │ │ │ └── GoogleTranslator.cs.meta │ │ │ ├── Translate.meta │ │ │ ├── VirtueSky.Sunflower.Localization.asmdef │ │ │ └── VirtueSky.Sunflower.Localization.asmdef.meta │ │ └── Runtime.meta │ ├── Localization.meta │ ├── Misc/ │ │ ├── Common.Animancer.cs │ │ ├── Common.Animancer.cs.meta │ │ ├── Common.Collections.cs │ │ ├── Common.Collections.cs.meta │ │ ├── Common.Colors.cs │ │ ├── Common.Colors.cs.meta │ │ ├── Common.Math.cs │ │ ├── Common.Math.cs.meta │ │ ├── Common.Physics.cs │ │ ├── Common.Physics.cs.meta │ │ ├── Common.SkeletonAnimation.cs │ │ ├── Common.SkeletonAnimation.cs.meta │ │ ├── Common.SkeletonGraphic.cs │ │ ├── Common.SkeletonGraphic.cs.meta │ │ ├── Common.Tag.cs │ │ ├── Common.Tag.cs.meta │ │ ├── Common.Text.cs │ │ ├── Common.Text.cs.meta │ │ ├── Common.Transform.cs │ │ ├── Common.Transform.cs.meta │ │ ├── Common.cs │ │ ├── Common.cs.meta │ │ ├── virtuesky.sunflower.misc.asmdef │ │ └── virtuesky.sunflower.misc.asmdef.meta │ ├── Misc.meta │ ├── Notifications/ │ │ ├── Editor/ │ │ │ ├── NotificationWindowEditor.cs │ │ │ ├── NotificationWindowEditor.cs.meta │ │ │ ├── Virtuesky.Sunflower.Notifications.Editor.asmdef │ │ │ └── Virtuesky.Sunflower.Notifications.Editor.asmdef.meta │ │ ├── Editor.meta │ │ ├── Runtime/ │ │ │ ├── NotificationAndroid.cs │ │ │ ├── NotificationAndroid.cs.meta │ │ │ ├── NotificationConsole.cs │ │ │ ├── NotificationConsole.cs.meta │ │ │ ├── NotificationIOS.cs │ │ │ ├── NotificationIOS.cs.meta │ │ │ ├── NotificationPrepare.cs │ │ │ ├── NotificationPrepare.cs.meta │ │ │ ├── NotificationVariable.cs │ │ │ ├── NotificationVariable.cs.meta │ │ │ ├── virtuesky.sunflower.notifications.asmdef │ │ │ └── virtuesky.sunflower.notifications.asmdef.meta │ │ └── Runtime.meta │ ├── Notifications.meta │ ├── ObjectPooling/ │ │ ├── Pool.cs │ │ ├── Pool.cs.meta │ │ ├── PoolData.cs │ │ ├── PoolData.cs.meta │ │ ├── PoolHandle.cs │ │ ├── PoolHandle.cs.meta │ │ ├── PooledObjectId.cs │ │ ├── PooledObjectId.cs.meta │ │ ├── virtuesky.sunflower.objectpooling.asmdef │ │ └── virtuesky.sunflower.objectpooling.asmdef.meta │ ├── ObjectPooling.meta │ ├── Rating/ │ │ ├── Editor/ │ │ │ ├── RatingWindowEditor.cs │ │ │ ├── RatingWindowEditor.cs.meta │ │ │ ├── Virtuesky.Sunflower.Rating.Editor.asmdef │ │ │ └── Virtuesky.Sunflower.Rating.Editor.asmdef.meta │ │ ├── Editor.meta │ │ ├── Runtime/ │ │ │ ├── InAppReview.cs │ │ │ ├── InAppReview.cs.meta │ │ │ ├── virtuesky.sunflower.rating.asmdef │ │ │ └── virtuesky.sunflower.rating.asmdef.meta │ │ └── Runtime.meta │ ├── Rating.meta │ ├── RemoteConfig/ │ │ ├── FirebaseRemoteConfigData.cs │ │ ├── FirebaseRemoteConfigData.cs.meta │ │ ├── FirebaseRemoteConfigManager.cs │ │ ├── FirebaseRemoteConfigManager.cs.meta │ │ ├── Virtuesky.Sunflower.RemoteConfigs.asmdef │ │ └── Virtuesky.Sunflower.RemoteConfigs.asmdef.meta │ ├── RemoteConfig.meta │ ├── SimpleJSON/ │ │ ├── SimpleJSON.cs │ │ ├── SimpleJSON.cs.meta │ │ ├── SimpleJSONBinary.cs │ │ ├── SimpleJSONBinary.cs.meta │ │ ├── SimpleJSONDotNetTypes.cs │ │ ├── SimpleJSONDotNetTypes.cs.meta │ │ ├── SimpleJSONUnity.cs │ │ ├── SimpleJSONUnity.cs.meta │ │ ├── Virtuesky.Sunflower.SimpleJson.asmdef │ │ └── Virtuesky.Sunflower.SimpleJson.asmdef.meta │ ├── SimpleJSON.meta │ ├── TouchInput/ │ │ ├── Editor/ │ │ │ ├── TouchInputManagerEditor.cs │ │ │ ├── TouchInputManagerEditor.cs.meta │ │ │ ├── Virtuesky.Sunflower.TouchInput.Editor.asmdef │ │ │ └── Virtuesky.Sunflower.TouchInput.Editor.asmdef.meta │ │ ├── Editor.meta │ │ ├── Runtime/ │ │ │ ├── InputTouchEvent/ │ │ │ │ ├── InputEventTouchBegin.cs │ │ │ │ ├── InputEventTouchBegin.cs.meta │ │ │ │ ├── InputEventTouchCancel.cs │ │ │ │ ├── InputEventTouchCancel.cs.meta │ │ │ │ ├── InputEventTouchEnd.cs │ │ │ │ ├── InputEventTouchEnd.cs.meta │ │ │ │ ├── InputEventTouchMove.cs │ │ │ │ ├── InputEventTouchMove.cs.meta │ │ │ │ ├── InputEventTouchStationary.cs │ │ │ │ ├── InputEventTouchStationary.cs.meta │ │ │ │ ├── InputPreventTouchVariable.cs │ │ │ │ └── InputPreventTouchVariable.cs.meta │ │ │ ├── InputTouchEvent.meta │ │ │ ├── TouchInputManager.cs │ │ │ ├── TouchInputManager.cs.meta │ │ │ ├── Virtuesky.Sunflower.TouchInput.asmdef │ │ │ └── Virtuesky.Sunflower.TouchInput.asmdef.meta │ │ └── Runtime.meta │ ├── TouchInput.meta │ ├── Tracking/ │ │ ├── Editor/ │ │ │ ├── TrackingWindowEditor.cs │ │ │ ├── TrackingWindowEditor.cs.meta │ │ │ ├── Virtuesky.Sunflower.TrackingEditor.asmdef │ │ │ └── Virtuesky.Sunflower.TrackingEditor.asmdef.meta │ │ ├── Editor.meta │ │ ├── Runtime/ │ │ │ ├── AdjustTracking/ │ │ │ │ ├── AdjustConfig.cs │ │ │ │ ├── AdjustConfig.cs.meta │ │ │ │ ├── AdjustTrackingRevenue.cs │ │ │ │ ├── AdjustTrackingRevenue.cs.meta │ │ │ │ ├── TrackingAdjust.cs │ │ │ │ └── TrackingAdjust.cs.meta │ │ │ ├── AdjustTracking.meta │ │ │ ├── AppTracking.cs │ │ │ ├── AppTracking.cs.meta │ │ │ ├── AppsFlyerTracking/ │ │ │ │ ├── AppsFlyerConfig.cs │ │ │ │ ├── AppsFlyerConfig.cs.meta │ │ │ │ ├── AppsFlyerObject.cs │ │ │ │ ├── AppsFlyerObject.cs.meta │ │ │ │ ├── AppsFlyerTrackingRevenue.cs │ │ │ │ ├── AppsFlyerTrackingRevenue.cs.meta │ │ │ │ ├── TrackingAppsFlyer.cs │ │ │ │ ├── TrackingAppsFlyer.cs.meta │ │ │ │ ├── TrackingAppsFlyerFiveParam.cs │ │ │ │ ├── TrackingAppsFlyerFiveParam.cs.meta │ │ │ │ ├── TrackingAppsFlyerFourParam.cs │ │ │ │ ├── TrackingAppsFlyerFourParam.cs.meta │ │ │ │ ├── TrackingAppsFlyerHasParam.cs │ │ │ │ ├── TrackingAppsFlyerHasParam.cs.meta │ │ │ │ ├── TrackingAppsFlyerNoParam.cs │ │ │ │ ├── TrackingAppsFlyerNoParam.cs.meta │ │ │ │ ├── TrackingAppsFlyerOneParam.cs │ │ │ │ ├── TrackingAppsFlyerOneParam.cs.meta │ │ │ │ ├── TrackingAppsFlyerThreeParam.cs │ │ │ │ ├── TrackingAppsFlyerThreeParam.cs.meta │ │ │ │ ├── TrackingAppsFlyerTwoParam.cs │ │ │ │ └── TrackingAppsFlyerTwoParam.cs.meta │ │ │ ├── AppsFlyerTracking.meta │ │ │ ├── FirebaseAnalyticTracking/ │ │ │ │ ├── FirebaseAnalyticTrackingRevenue.cs │ │ │ │ ├── FirebaseAnalyticTrackingRevenue.cs.meta │ │ │ │ ├── TrackingFirebase.cs │ │ │ │ ├── TrackingFirebase.cs.meta │ │ │ │ ├── TrackingFirebaseFiveParam.cs │ │ │ │ ├── TrackingFirebaseFiveParam.cs.meta │ │ │ │ ├── TrackingFirebaseFourParam.cs │ │ │ │ ├── TrackingFirebaseFourParam.cs.meta │ │ │ │ ├── TrackingFirebaseNoParam.cs │ │ │ │ ├── TrackingFirebaseNoParam.cs.meta │ │ │ │ ├── TrackingFirebaseOneParam.cs │ │ │ │ ├── TrackingFirebaseOneParam.cs.meta │ │ │ │ ├── TrackingFirebaseSixParam.cs │ │ │ │ ├── TrackingFirebaseSixParam.cs.meta │ │ │ │ ├── TrackingFirebaseThreeParam.cs │ │ │ │ ├── TrackingFirebaseThreeParam.cs.meta │ │ │ │ ├── TrackingFirebaseTwoParam.cs │ │ │ │ └── TrackingFirebaseTwoParam.cs.meta │ │ │ ├── FirebaseAnalyticTracking.meta │ │ │ ├── Virtuesky.Sunflower.Tracking.asmdef │ │ │ └── Virtuesky.Sunflower.Tracking.asmdef.meta │ │ └── Runtime.meta │ ├── Tracking.meta │ ├── Utils/ │ │ ├── Editor/ │ │ │ ├── ConstantDefineSymbols.cs │ │ │ ├── ConstantDefineSymbols.cs.meta │ │ │ ├── CreateAsset.cs │ │ │ ├── CreateAsset.cs.meta │ │ │ ├── EditorCoroutine.cs │ │ │ ├── EditorCoroutine.cs.meta │ │ │ ├── EditorGUIUtils.cs │ │ │ ├── EditorGUIUtils.cs.meta │ │ │ ├── EditorGeneric.cs │ │ │ ├── EditorGeneric.cs.meta │ │ │ ├── EditorResources.cs │ │ │ ├── EditorResources.cs.meta │ │ │ ├── EditorScriptDefineSymbols.cs │ │ │ ├── EditorScriptDefineSymbols.cs.meta │ │ │ ├── ExSearchWindow.cs │ │ │ ├── ExSearchWindow.cs.meta │ │ │ ├── FileExtension.cs │ │ │ ├── FileExtension.cs.meta │ │ │ ├── GameViewUtils.cs │ │ │ ├── GameViewUtils.cs.meta │ │ │ ├── Icons/ │ │ │ │ ├── box_bg_dark.psd │ │ │ │ ├── box_bg_dark.psd.meta │ │ │ │ ├── box_content_dark.psd │ │ │ │ ├── box_content_dark.psd.meta │ │ │ │ ├── even_bg.png.meta │ │ │ │ ├── even_bg_dark.png.meta │ │ │ │ ├── even_bg_select.png.meta │ │ │ │ ├── icon_about.png.meta │ │ │ │ ├── icon_adjust.png.meta │ │ │ │ ├── icon_ads.png.meta │ │ │ │ ├── icon_appsflyer.png.meta │ │ │ │ ├── icon_audio.png.meta │ │ │ │ ├── icon_authentication.png.meta │ │ │ │ ├── icon_button.png.meta │ │ │ │ ├── icon_controller.png.meta │ │ │ │ ├── icon_csharp.png.meta │ │ │ │ ├── icon_extension.png.meta │ │ │ │ ├── icon_firebase.png.meta │ │ │ │ ├── icon_folder.png.meta │ │ │ │ ├── icon_game_service.png.meta │ │ │ │ ├── icon_gamemanager.png.meta │ │ │ │ ├── icon_generator.png.meta │ │ │ │ ├── icon_hierarchy.png.meta │ │ │ │ ├── icon_iap.png.meta │ │ │ │ ├── icon_in_app_review.png.meta │ │ │ │ ├── icon_leaderboard.png.meta │ │ │ │ ├── icon_locale.png.meta │ │ │ │ ├── icon_manager.png.meta │ │ │ │ ├── icon_package.png.meta │ │ │ │ ├── icon_scriptable.png.meta │ │ │ │ ├── icon_service.png.meta │ │ │ │ ├── icon_sound.png.meta │ │ │ │ ├── icon_sound_mixer.png.meta │ │ │ │ ├── icon_unity.png.meta │ │ │ │ ├── script_noti.png.meta │ │ │ │ ├── scriptable_adjust.png.meta │ │ │ │ ├── scriptable_adjust2.png.meta │ │ │ │ ├── scriptable_af.png.meta │ │ │ │ ├── scriptable_audio.png.meta │ │ │ │ ├── scriptable_audioclip.png.meta │ │ │ │ ├── scriptable_event.png.meta │ │ │ │ ├── scriptable_event_listener.png.meta │ │ │ │ ├── scriptable_factory.png.meta │ │ │ │ ├── scriptable_firebase.png.meta │ │ │ │ ├── scriptable_iap.png.meta │ │ │ │ ├── scriptable_notification.png.meta │ │ │ │ ├── scriptable_particle_system.png.meta │ │ │ │ ├── scriptable_pool.png.meta │ │ │ │ ├── scriptable_variable.png.meta │ │ │ │ ├── scriptable_yellow_audioclip.png.meta │ │ │ │ ├── scriptable_yellow_font.png.meta │ │ │ │ ├── scriptable_yellow_fontasset.png.meta │ │ │ │ ├── scriptable_yellow_gameobject.png.meta │ │ │ │ ├── scriptable_yellow_material.png.meta │ │ │ │ ├── scriptable_yellow_sprite.png.meta │ │ │ │ ├── scriptable_yellow_text.png.meta │ │ │ │ ├── scriptable_yellow_textasset.png.meta │ │ │ │ ├── scriptable_yellow_texture.png.meta │ │ │ │ ├── scriptable_yellow_videoclip.png.meta │ │ │ │ └── virtuesky_removebg.png.meta │ │ │ ├── Icons.meta │ │ │ ├── RegistryManager.cs │ │ │ ├── RegistryManager.cs.meta │ │ │ ├── TemplateAssembly/ │ │ │ │ ├── PurchasingGeneratedAsmdef.txt │ │ │ │ ├── PurchasingGeneratedAsmdef.txt.meta │ │ │ │ ├── PurchasingGeneratedAsmdefMeta.txt │ │ │ │ └── PurchasingGeneratedAsmdefMeta.txt.meta │ │ │ ├── TemplateAssembly.meta │ │ │ ├── TextureUtils.cs │ │ │ ├── TextureUtils.cs.meta │ │ │ ├── Uniform.cs │ │ │ ├── Uniform.cs.meta │ │ │ ├── UnityPackage/ │ │ │ │ ├── Note_Package.txt │ │ │ │ ├── Note_Package.txt.meta │ │ │ │ ├── google-play-game.unitypackage │ │ │ │ ├── google-play-game.unitypackage.meta │ │ │ │ ├── max-sdk.unitypackage │ │ │ │ └── max-sdk.unitypackage.meta │ │ │ ├── UnityPackage.meta │ │ │ ├── Virtuesky.Sunflower.UtilsEdtitor.asmdef │ │ │ └── Virtuesky.Sunflower.UtilsEdtitor.asmdef.meta │ │ ├── Editor.meta │ │ ├── Runtime/ │ │ │ ├── ColorExtensions.cs │ │ │ ├── ColorExtensions.cs.meta │ │ │ ├── ExtensionUtils.cs │ │ │ ├── ExtensionUtils.cs.meta │ │ │ ├── InputUtils.cs │ │ │ ├── InputUtils.cs.meta │ │ │ ├── InterfaceUtils.cs │ │ │ ├── InterfaceUtils.cs.meta │ │ │ ├── ReflectionUtils.cs │ │ │ ├── ReflectionUtils.cs.meta │ │ │ ├── ScriptableSettings.cs │ │ │ ├── ScriptableSettings.cs.meta │ │ │ ├── SimpleMath.cs │ │ │ ├── SimpleMath.cs.meta │ │ │ ├── StoreUtils.cs │ │ │ ├── StoreUtils.cs.meta │ │ │ ├── TimeUtils.cs │ │ │ ├── TimeUtils.cs.meta │ │ │ ├── TweenStatic.cs │ │ │ ├── TweenStatic.cs.meta │ │ │ ├── Virtuesky.Sunflower.Utils.asmdef │ │ │ └── Virtuesky.Sunflower.Utils.asmdef.meta │ │ └── Runtime.meta │ ├── Utils.meta │ ├── Variables/ │ │ ├── Editor/ │ │ │ ├── VariableGenerateGuid.cs │ │ │ ├── VariableGenerateGuid.cs.meta │ │ │ ├── VariableWindowEditor.cs │ │ │ ├── VariableWindowEditor.cs.meta │ │ │ ├── virtuesky.sunflower.variable.Editor.asmdef │ │ │ └── virtuesky.sunflower.variable.Editor.asmdef.meta │ │ ├── Editor.meta │ │ ├── Runtime/ │ │ │ ├── Base_Variable/ │ │ │ │ ├── BaseReference.cs │ │ │ │ ├── BaseReference.cs.meta │ │ │ │ ├── BaseVariable.cs │ │ │ │ ├── BaseVariable.cs.meta │ │ │ │ ├── BaseVariableListener.cs │ │ │ │ ├── BaseVariableListener.cs.meta │ │ │ │ ├── IGuidVariable.cs │ │ │ │ └── IGuidVariable.cs.meta │ │ │ ├── Base_Variable.meta │ │ │ ├── Boolean_Variable/ │ │ │ │ ├── BooleanReference.cs │ │ │ │ ├── BooleanReference.cs.meta │ │ │ │ ├── BooleanVariable.cs │ │ │ │ ├── BooleanVariable.cs.meta │ │ │ │ ├── BooleanVariableListener.cs │ │ │ │ └── BooleanVariableListener.cs.meta │ │ │ ├── Boolean_Variable.meta │ │ │ ├── Float_Variable/ │ │ │ │ ├── FloatReference.cs │ │ │ │ ├── FloatReference.cs.meta │ │ │ │ ├── FloatVariable.cs │ │ │ │ ├── FloatVariable.cs.meta │ │ │ │ ├── FloatVariableListener.cs │ │ │ │ └── FloatVariableListener.cs.meta │ │ │ ├── Float_Variable.meta │ │ │ ├── Integer_Variable/ │ │ │ │ ├── IntegerReference.cs │ │ │ │ ├── IntegerReference.cs.meta │ │ │ │ ├── IntegerVariable.cs │ │ │ │ ├── IntegerVariable.cs.meta │ │ │ │ ├── IntegerVariableListener.cs │ │ │ │ └── IntegerVariableListener.cs.meta │ │ │ ├── Integer_Variable.meta │ │ │ ├── Interface_Variable/ │ │ │ │ ├── IReference.cs │ │ │ │ ├── IReference.cs.meta │ │ │ │ ├── IVariable.cs │ │ │ │ └── IVariable.cs.meta │ │ │ ├── Interface_Variable.meta │ │ │ ├── Object_Variable/ │ │ │ │ ├── ObjectReference.cs │ │ │ │ ├── ObjectReference.cs.meta │ │ │ │ ├── ObjectVariable.cs │ │ │ │ ├── ObjectVariable.cs.meta │ │ │ │ ├── ObjectVariableListener.cs │ │ │ │ └── ObjectVariableListener.cs.meta │ │ │ ├── Object_Variable.meta │ │ │ ├── Rect_Variable/ │ │ │ │ ├── RectVariable.cs │ │ │ │ └── RectVariable.cs.meta │ │ │ ├── Rect_Variable.meta │ │ │ ├── ShortDouble_Variable/ │ │ │ │ ├── ShortDoubleReference.cs │ │ │ │ ├── ShortDoubleReference.cs.meta │ │ │ │ ├── ShortDoubleVariable.cs │ │ │ │ ├── ShortDoubleVariable.cs.meta │ │ │ │ ├── ShortDoubleVariableListener.cs │ │ │ │ └── ShortDoubleVariableListener.cs.meta │ │ │ ├── ShortDouble_Variable.meta │ │ │ ├── String_Variable/ │ │ │ │ ├── StringVariable.cs │ │ │ │ ├── StringVariable.cs.meta │ │ │ │ ├── StringVariableListener.cs │ │ │ │ └── StringVariableListener.cs.meta │ │ │ ├── String_Variable.meta │ │ │ ├── Trasform_Variable/ │ │ │ │ ├── TransformReference.cs │ │ │ │ ├── TransformReference.cs.meta │ │ │ │ ├── TransformVariable.cs │ │ │ │ └── TransformVariable.cs.meta │ │ │ ├── Trasform_Variable.meta │ │ │ ├── Vector2_Variable/ │ │ │ │ ├── Vector2Reference.cs │ │ │ │ ├── Vector2Reference.cs.meta │ │ │ │ ├── Vector2Variable.cs │ │ │ │ ├── Vector2Variable.cs.meta │ │ │ │ ├── Vector2VariableListener.cs │ │ │ │ └── Vector2VariableListener.cs.meta │ │ │ ├── Vector2_Variable.meta │ │ │ ├── Vector3_Variable/ │ │ │ │ ├── Vector3Reference.cs │ │ │ │ ├── Vector3Reference.cs.meta │ │ │ │ ├── Vector3Variable.cs │ │ │ │ ├── Vector3Variable.cs.meta │ │ │ │ ├── Vector3VariableListener.cs │ │ │ │ └── Vector3VariableListener.cs.meta │ │ │ ├── Vector3_Variable.meta │ │ │ ├── virtuesky.sunflower.variable.asmdef │ │ │ └── virtuesky.sunflower.variable.asmdef.meta │ │ └── Runtime.meta │ ├── Variables.meta │ ├── Vibration/ │ │ ├── Plugins/ │ │ │ ├── iOS/ │ │ │ │ ├── Vibration/ │ │ │ │ │ ├── HapticFeedback.mm │ │ │ │ │ ├── HapticFeedback.mm.meta │ │ │ │ │ ├── Vibration.h │ │ │ │ │ ├── Vibration.h.meta │ │ │ │ │ ├── Vibration.mm │ │ │ │ │ └── Vibration.mm.meta │ │ │ │ └── Vibration.meta │ │ │ └── iOS.meta │ │ ├── Plugins.meta │ │ ├── README.md │ │ ├── README.md.meta │ │ ├── Vibration.cs │ │ ├── Vibration.cs.meta │ │ ├── virtuesky.sunflower.vibration.asmdef │ │ └── virtuesky.sunflower.vibration.asmdef.meta │ └── Vibration.meta ├── VirtueSky.meta ├── package.json └── package.json.meta ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/workflows/notify-discord-on-release.yml ================================================ name: Notify Discord on Release or Tag on: release: types: [published] push: tags: - '*' jobs: notify-discord: runs-on: ubuntu-latest steps: - name: Send release/tag info to Discord env: DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }} EVENT_NAME: ${{ github.event_name }} RELEASE_TITLE: ${{ github.event.release.name }} RELEASE_TAG_NAME: ${{ github.event.release.tag_name }} RELEASE_NOTE: ${{ github.event.release.body }} RELEASE_AUTHOR: ${{ github.event.release.author.login }} PUSH_TAG_NAME: ${{ github.ref_name }} REPO: ${{ github.repository }} ACTOR: ${{ github.actor }} run: | if [ "$EVENT_NAME" = "release" ]; then TITLE="${RELEASE_TITLE:-No release title}" TAG="${RELEASE_TAG_NAME:-Unknown tag}" NOTE="${RELEASE_NOTE}" AUTHOR="${RELEASE_AUTHOR:-$ACTOR}" EVENT_LABEL="GitHub Release" else TITLE="Tag created" TAG="${PUSH_TAG_NAME:-Unknown tag}" NOTE="A new tag was pushed without creating a GitHub Release." AUTHOR="$ACTOR" EVENT_LABEL="Git Tag" fi if [ -z "$NOTE" ]; then NOTE="(empty)" fi if [ ${#NOTE} -gt 1000 ]; then NOTE="${NOTE:0:1000}..." fi jq -n \ --arg event "$EVENT_LABEL" \ --arg title "$TITLE" \ --arg tag "$TAG" \ --arg note "$NOTE" \ --arg repo "$REPO" \ --arg actor "$ACTOR" \ --arg author "$AUTHOR" \ '{ embeds: [ { title: $event, fields: [ { "name": "Repository", "value": $repo, "inline": false }, { "name": "Triggered By", "value": $actor, "inline": false }, { "name": "Author", "value": $author, "inline": false }, { "name": "Title", "value": $title, "inline": false }, { "name": "Tag Name", "value": $tag, "inline": false }, { "name": "Note", "value": $note, "inline": false } ] } ] }' > payload.json cat payload.json curl --fail-with-body \ -H "Content-Type: application/json" \ -X POST \ -d @payload.json \ "$DISCORD_WEBHOOK_URL" ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2024 VirtueSky Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: LICENSE.meta ================================================ fileFormatVersion: 2 guid: 602f2b07fec879a41853f704b2b884a5 DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: README.md ================================================ # Core scriptable object architecture for building Unity games (Android & iOS)

Made With Unity License Last Commit Repo Size Last Release

### Unity 2022.3 LTS ## How To Install ### 1: Download the repository and drop it into folder `Assets` ### 2: Add the line below to `Packages/manifest.json` - for version `3.5.4` ```json { "scopedRegistries": [ { "name": "npm", "url": "https://registry.npmjs.org/", "scopes": [ "com.kyrylokuzyk" ] } ], "dependencies": { "com.virtuesky.sunflower":"https://github.com/VirtueSky/sunflower.git#3.5.4" } } ``` - depencies: ```json "com.unity.nuget.newtonsoft-json": "3.2.1", "com.unity.serialization": "3.1.1", "com.unity.collections": "2.1.4", "com.unity.textmeshpro": "3.0.8", "com.cysharp.unitask": "https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask#2.5.10", "com.kyrylokuzyk.primetween": "1.3.8", ``` ## Includes modules ```bash ├── Core (Update only called once in Monobehaviour, Delay...) ├── Advertising (Support for Max, Admob and IronSource) ├── In App Purchase (IAP) ├── Asset Finder ├── Audio ├── Button ├── Data ├── Scriptable Event ├── Scriptable Variable ├── Firebase Remote Config ├── Tracking (Firebase Analytics, Adjust, AppsFlyer) ├── Tri-Inspector ├── Level Editor ├── Mobile Notification ├── Object Pooling ├── Localization ├── FolderIcons ├── Hierarchy ├── In app review ├── SimpleJSON ├── Tracking Revenue (by Firebase analytic, Adjust or Appsflyer) ├── Vibration (Vibration native support for android & ios) ├── Game Service (Sign in with apple id / google play games service) ├── Misc (Extension support Transform, SafeArea, Play Animancer, Skeleton,...) ├── Touch Input ├── Component ``` #### Note: - [See Document](https://github.com/VirtueSky/sunflower/wiki) - [Project implementation](https://github.com/VirtueSky/TheBeginning) - [Core has similar modules but does not use scriptable architecture](https://github.com/wolf-package/unity-common) [Join Discord to receive update notifications](https://discord.gg/bpcUyHRZ) ================================================ FILE: README.md.meta ================================================ fileFormatVersion: 2 guid: 7b4ab53c22cea684aa8898738b406520 TextScriptImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Advertising/Editor/AdSettingEditor.cs ================================================ #if UNITY_EDITOR using System; using UnityEditor; using UnityEngine; using VirtueSky.Inspector; using VirtueSky.UtilsEditor; namespace VirtueSky.Ads { [CustomEditor(typeof(AdSetting), true)] public class AdSettingEditor : Editor { private AdSetting _adSetting; private SerializedProperty _useApplovin; private SerializedProperty _useAdmob; private SerializedProperty _useLevelPlay; private SerializedProperty _enableTrackAdRevenue; private SerializedProperty _adCheckingInterval; private SerializedProperty _adLoadingInterval; private SerializedProperty _sdkKey; private SerializedProperty _maxBannerVariable; private SerializedProperty _maxInterVariable; private SerializedProperty _maxRewardVariable; private SerializedProperty _maxAppOpenVariable; private SerializedProperty _admobBannerVariable; private SerializedProperty _admobInterVariable; private SerializedProperty _admobRewardVariable; private SerializedProperty _admobRewardInterVariable; private SerializedProperty _admobAppOpenVariable; private SerializedProperty _admobNativeOverlayVariable; private SerializedProperty _autoTrackingAdImpressionAdmob; private SerializedProperty _admobEnableTestMode; private SerializedProperty _enableGDPR; private SerializedProperty _enableGDPRTestMode; private SerializedProperty _admobDevicesTest; private SerializedProperty _androidAppKey; private SerializedProperty _iOSAppKey; private SerializedProperty _useTestAppKey; private SerializedProperty _levelPlayBannerVariable; private SerializedProperty _levelPlayInterVariable; private SerializedProperty _levelPlayRewardVariable; const string pathMax = "/Ads/Applovin"; const string pathAdmob = "/Ads/Admob"; const string pathIronSource = "/Ads/LevelPlay"; void Initialize() { _adSetting = target as AdSetting; _useApplovin = serializedObject.FindProperty("useAppLovin"); _useAdmob = serializedObject.FindProperty("useAdmob"); _useLevelPlay = serializedObject.FindProperty("useLevelPlay"); _enableTrackAdRevenue = serializedObject.FindProperty("enableTrackAdRevenue"); _adCheckingInterval = serializedObject.FindProperty("adCheckingInterval"); _adLoadingInterval = serializedObject.FindProperty("adLoadingInterval"); _sdkKey = serializedObject.FindProperty("sdkKey"); _maxBannerVariable = serializedObject.FindProperty("maxBannerVariable"); _maxInterVariable = serializedObject.FindProperty("maxInterVariable"); _maxRewardVariable = serializedObject.FindProperty("maxRewardVariable"); _maxAppOpenVariable = serializedObject.FindProperty("maxAppOpenVariable"); _admobBannerVariable = serializedObject.FindProperty("admobBannerVariable"); _admobInterVariable = serializedObject.FindProperty("admobInterVariable"); _admobRewardVariable = serializedObject.FindProperty("admobRewardVariable"); _admobRewardInterVariable = serializedObject.FindProperty("admobRewardInterVariable"); _admobAppOpenVariable = serializedObject.FindProperty("admobAppOpenVariable"); _admobNativeOverlayVariable = serializedObject.FindProperty("admobNativeOverlayVariable"); _autoTrackingAdImpressionAdmob = serializedObject.FindProperty("autoTrackingAdImpressionAdmob"); _admobEnableTestMode = serializedObject.FindProperty("admobEnableTestMode"); _admobDevicesTest = serializedObject.FindProperty("admobDevicesTest"); _enableGDPR = serializedObject.FindProperty("enableGDPR"); _enableGDPRTestMode = serializedObject.FindProperty("enableGDPRTestMode"); _androidAppKey = serializedObject.FindProperty("androidAppKey"); _iOSAppKey = serializedObject.FindProperty("iOSAppKey"); _useTestAppKey = serializedObject.FindProperty("useTestAppKey"); _levelPlayBannerVariable = serializedObject.FindProperty("levelPlayBannerVariable"); _levelPlayInterVariable = serializedObject.FindProperty("levelPlayInterVariable"); _levelPlayRewardVariable = serializedObject.FindProperty("levelPlayRewardVariable"); } void Draw() { serializedObject.Update(); Initialize(); // EditorGUILayout.LabelField("ADS SETTING", EditorStyles.boldLabel); //GuiLine(2); GUILayout.Space(10); EditorGUILayout.PropertyField(_adCheckingInterval); EditorGUILayout.PropertyField(_adLoadingInterval); EditorGUILayout.PropertyField(_useApplovin); EditorGUILayout.PropertyField(_useAdmob); EditorGUILayout.PropertyField(_useLevelPlay); EditorGUILayout.PropertyField(_enableTrackAdRevenue); EditorGUILayout.PropertyField(_enableGDPR); if (_enableGDPR.boolValue) { EditorGUILayout.PropertyField(_enableGDPRTestMode); } GUILayout.Space(10); if (_useApplovin.boolValue) SetupMax(); if (_useAdmob.boolValue) SetupAdmob(); if (_useLevelPlay.boolValue) SetupIronSource(); EditorUtility.SetDirty(target); serializedObject.ApplyModifiedProperties(); } public override void OnInspectorGUI() { Draw(); } void SetupMax() { EditorGUILayout.LabelField("Applovin - Max", StyleLabel()); GuiLine(1); GUILayout.Space(10); EditorGUILayout.PropertyField(_sdkKey); EditorGUILayout.BeginHorizontal(); EditorGUILayout.PropertyField(_maxBannerVariable); if (_maxBannerVariable.objectReferenceValue == null) { GUILayout.Space(2); if (GUILayout.Button("Create", GUILayout.Width(55))) { _maxBannerVariable.objectReferenceValue = CreateAsset.CreateAndGetScriptableAsset(pathMax); } } EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.PropertyField(_maxInterVariable); if (_maxInterVariable.objectReferenceValue == null) { GUILayout.Space(2); if (GUILayout.Button("Create", GUILayout.Width(55))) { _maxInterVariable.objectReferenceValue = CreateAsset.CreateAndGetScriptableAsset(pathMax); } } EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.PropertyField(_maxRewardVariable); if (_maxRewardVariable.objectReferenceValue == null) { GUILayout.Space(2); if (GUILayout.Button("Create", GUILayout.Width(55))) { _maxRewardVariable.objectReferenceValue = CreateAsset.CreateAndGetScriptableAsset(pathMax); } } EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.PropertyField(_maxAppOpenVariable); if (_maxAppOpenVariable.objectReferenceValue == null) { GUILayout.Space(2); if (GUILayout.Button("Create", GUILayout.Width(55))) { _maxAppOpenVariable.objectReferenceValue = CreateAsset.CreateAndGetScriptableAsset(pathMax); } } EditorGUILayout.EndHorizontal(); GUILayout.Space(10); } void SetupAdmob() { EditorGUILayout.LabelField("Google - Admob", StyleLabel()); GuiLine(1); GUILayout.Space(10); EditorGUILayout.BeginHorizontal(); EditorGUILayout.PropertyField(_admobBannerVariable); if (_admobBannerVariable.objectReferenceValue == null) { GUILayout.Space(2); if (GUILayout.Button("Create", GUILayout.Width(55))) { _admobBannerVariable.objectReferenceValue = CreateAsset.CreateAndGetScriptableAsset(pathAdmob); } } EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.PropertyField(_admobInterVariable); if (_admobInterVariable.objectReferenceValue == null) { GUILayout.Space(2); if (GUILayout.Button("Create", GUILayout.Width(55))) { _admobInterVariable.objectReferenceValue = CreateAsset.CreateAndGetScriptableAsset(pathAdmob); } } EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.PropertyField(_admobRewardVariable); if (_admobRewardVariable.objectReferenceValue == null) { GUILayout.Space(2); if (GUILayout.Button("Create", GUILayout.Width(55))) { _admobRewardVariable.objectReferenceValue = CreateAsset.CreateAndGetScriptableAsset(pathAdmob); } } EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.PropertyField(_admobRewardInterVariable); if (_admobRewardInterVariable.objectReferenceValue == null) { GUILayout.Space(2); if (GUILayout.Button("Create", GUILayout.Width(55))) { _admobRewardInterVariable.objectReferenceValue = CreateAsset .CreateAndGetScriptableAsset(pathAdmob); } } EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.PropertyField(_admobAppOpenVariable); if (_admobAppOpenVariable.objectReferenceValue == null) { GUILayout.Space(2); if (GUILayout.Button("Create", GUILayout.Width(55))) { _admobAppOpenVariable.objectReferenceValue = CreateAsset.CreateAndGetScriptableAsset(pathAdmob); } } EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.PropertyField(_admobNativeOverlayVariable); if (_admobNativeOverlayVariable.objectReferenceValue == null) { GUILayout.Space(2); if (GUILayout.Button("Create", GUILayout.Width(55))) { _admobNativeOverlayVariable.objectReferenceValue = CreateAsset.CreateAndGetScriptableAsset(pathAdmob); } } EditorGUILayout.EndHorizontal(); EditorGUILayout.PropertyField(_autoTrackingAdImpressionAdmob); EditorGUILayout.PropertyField(_admobEnableTestMode); EditorGUILayout.PropertyField(_admobDevicesTest); GUI.enabled = false; EditorGUILayout.TextField("App Id Test", "ca-app-pub-3940256099942544~3347511713"); GUI.enabled = true; GUILayout.Space(10); if (GUILayout.Button("Open GoogleAdmobSetting", GUILayout.Height(20))) { EditorApplication.ExecuteMenuItem("Assets/Google Mobile Ads/Settings..."); } GUILayout.Space(10); } void SetupIronSource() { EditorGUILayout.LabelField("Unity - LevelPlay", StyleLabel()); GuiLine(1); GUILayout.Space(10); EditorGUILayout.PropertyField(_androidAppKey); EditorGUILayout.PropertyField(_iOSAppKey); EditorGUILayout.PropertyField(_useTestAppKey); EditorGUILayout.BeginHorizontal(); EditorGUILayout.PropertyField(_levelPlayBannerVariable); if (_levelPlayBannerVariable.objectReferenceValue == null) { GUILayout.Space(2); if (GUILayout.Button("Create", GUILayout.Width(55))) { _levelPlayBannerVariable.objectReferenceValue = CreateAsset.CreateAndGetScriptableAsset(pathIronSource); } } EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.PropertyField(_levelPlayInterVariable); if (_levelPlayInterVariable.objectReferenceValue == null) { GUILayout.Space(2); if (GUILayout.Button("Create", GUILayout.Width(55))) { _levelPlayInterVariable.objectReferenceValue = CreateAsset.CreateAndGetScriptableAsset(pathIronSource); } } EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.PropertyField(_levelPlayRewardVariable); if (_levelPlayRewardVariable.objectReferenceValue == null) { GUILayout.Space(2); if (GUILayout.Button("Create", GUILayout.Width(55))) { _levelPlayRewardVariable.objectReferenceValue = CreateAsset.CreateAndGetScriptableAsset(pathIronSource); } } EditorGUILayout.EndHorizontal(); GUILayout.Space(10); } GUIStyle StyleLabel() { var style = new GUIStyle(); style.fontSize = 14; style.normal.textColor = Color.white; return style; } void GuiLine(int i_height = 1) { Rect rect = EditorGUILayout.GetControlRect(false, i_height); rect.height = i_height; EditorGUI.DrawRect(rect, new Color32(0, 0, 0, 255)); } } } #endif ================================================ FILE: VirtueSky/Advertising/Editor/AdSettingEditor.cs.meta ================================================ fileFormatVersion: 2 guid: 6439b65cc7b34375ace31c6d3f331f3e timeCreated: 1700021422 ================================================ FILE: VirtueSky/Advertising/Editor/AdsWindowEditor.cs ================================================ #if UNITY_EDITOR using UnityEditor; using UnityEngine; using VirtueSky.Inspector; using VirtueSky.UtilsEditor; namespace VirtueSky.Ads { public class AdsWindowEditor : EditorWindow { // private Vector2 _scrollPosition; // private Editor _editor; // // private AdSetting _adSetting; // // private bool isSetupTheme = false; // // [MenuItem("Sunflower/Ads/AdSetting &4", false)] // public static void OpenAdSettingsWindows() // { // var adSetting = // CreateAsset.CreateAndGetScriptableAsset("/Ads"); // AdsWindowEditor adWindow = GetWindow("Ads Settings"); // adWindow._adSetting = adSetting; // if (adWindow == null) // { // Debug.LogError("Couldn't open the ads settings window!"); // return; // } // // adWindow.minSize = new Vector2(275, 0); // adWindow.Show(); // EditorGUIUtility.PingObject(adSetting); // } // // private void OnGUI() // { // EditorGUI.DrawRect(new Rect(0, 0, position.width, position.height), // GameDataEditor.ColorBackgroundRectWindowSunflower.ToColor()); // GUI.contentColor = GameDataEditor.ColorTextContentWindowSunflower.ToColor(); // GUI.backgroundColor = GameDataEditor.ColorContentWindowSunflower.ToColor(); // if (_editor == null) _editor = UnityEditor.Editor.CreateEditor(_adSetting); // // if (_editor == null) // { // EditorGUILayout.HelpBox("Couldn't create the settings resources editor.", // MessageType.Error); // return; // } // // // _editor.DrawHeader(); // _scrollPosition = EditorGUILayout.BeginScrollView(_scrollPosition); // EditorGUILayout.BeginVertical(new GUIStyle { padding = new RectOffset(6, 3, 3, 3) }); // _editor.OnInspectorGUI(); // // GUILayout.Space(10); // Handles.color = Color.black; // Handles.DrawAAPolyLine(3, new Vector3(0, GUILayoutUtility.GetLastRect().y + 10), // new Vector3(position.width, GUILayoutUtility.GetLastRect().y + 10)); // GUILayout.Space(10); // // // EditorGUILayout.EndVertical(); // EditorGUILayout.EndScrollView(); // } // // #region Applovin // // private const string pathMax = "/Ads/Applovin"; // // [MenuItem("Sunflower/Ads/Applovin/Max Client")] // public static void CreateMaxClient() // { // CreateAsset.CreateScriptableAssets(pathMax, "max_ad_client"); // } // // [MenuItem("Sunflower/Ads/Applovin/Max Banner")] // public static void CreateMaxBanner() // { // CreateAsset.CreateScriptableAssets(pathMax, "max_banner_variable"); // } // // [MenuItem("Sunflower/Ads/Applovin/Max Inter")] // public static void CreateMaxInter() // { // CreateAsset.CreateScriptableAssets(pathMax, "max_inter_variable"); // } // // [MenuItem("Sunflower/Ads/Applovin/Max Reward")] // public static void CreateMaxReward() // { // CreateAsset.CreateScriptableAssets(pathMax, "max_reward_variable"); // } // // [MenuItem("Sunflower/Ads/Applovin/Max App Open")] // public static void CreateMaxAppOpen() // { // CreateAsset.CreateScriptableAssets(pathMax, // "max_app_open_variable"); // } // // [MenuItem("Sunflower/Ads/Applovin/Max Reward Inter")] // public static void CreateMaxRewardInter() // { // CreateAsset.CreateScriptableAssets(pathMax, // "max_reward_inter_variable"); // } // // #endregion // // #region Admob // // private const string pathAdmob = "/Ads/Admob"; // // [MenuItem("Sunflower/Ads/Admob/Admob Client")] // public static void CreateAdmobClient() // { // CreateAsset.CreateScriptableAssets(pathAdmob, "admob_ad_client"); // } // // [MenuItem("Sunflower/Ads/Admob/Admob Banner")] // public static void CreateAdmobBanner() // { // CreateAsset.CreateScriptableAssets(pathAdmob, // "admob_banner_variable"); // } // // [MenuItem("Sunflower/Ads/Admob/Admob Inter")] // public static void CreateAdmobInter() // { // CreateAsset.CreateScriptableAssets(pathAdmob, // "admob_inter_variable"); // } // // [MenuItem("Sunflower/Ads/Admob/Admob Reward")] // public static void CreateAdmobReward() // { // CreateAsset.CreateScriptableAssets(pathAdmob, // "admob_reward_variable"); // } // // [MenuItem("Sunflower/Ads/Admob/Admob App Open")] // public static void CreateAdmobAppOpen() // { // CreateAsset.CreateScriptableAssets(pathAdmob, // "admob_app_open_variable"); // } // // [MenuItem("Sunflower/Ads/Admob/Admob Reward Inter")] // public static void CreateAdmobRewardInter() // { // CreateAsset.CreateScriptableAssets(pathAdmob, // "admob_reward_inter_variable"); // } // // #endregion } } #endif ================================================ FILE: VirtueSky/Advertising/Editor/AdsWindowEditor.cs.meta ================================================ fileFormatVersion: 2 guid: 6fd65ccaee60423bbab98afe628d2016 timeCreated: 1695461341 ================================================ FILE: VirtueSky/Advertising/Editor/Virtuesky.Sunflower.Advertising.Editor.asmdef ================================================ { "name": "Virtuesky.Sunflower.Advertising.Editor", "rootNamespace": "", "references": [ "GUID:abd57f653a468a04c8d4e281527ff293", "GUID:c904f6d969e991d459a0843b71c22ec5", "GUID:324caed91501a9c47a04ebfd87b68794", "GUID:0b6289df6f84a6f4b982ff72d23e0273" ], "includePlatforms": [ "Editor" ], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], "versionDefines": [], "noEngineReferences": false } ================================================ FILE: VirtueSky/Advertising/Editor/Virtuesky.Sunflower.Advertising.Editor.asmdef.meta ================================================ fileFormatVersion: 2 guid: ea1af3c654880af4ca6bb44b012e055e AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Advertising/Editor.meta ================================================ fileFormatVersion: 2 guid: c0fa69d79e042904290c060082316cf1 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Advertising/Runtime/Admob/AdmobAdClient.cs ================================================ #if VIRTUESKY_ADS && VIRTUESKY_ADMOB using GoogleMobileAds.Api; #endif using VirtueSky.Core; using VirtueSky.Tracking; namespace VirtueSky.Ads { public sealed class AdmobAdClient : AdClient { public AdmobAdClient(AdSetting _adSetting) { adSetting = _adSetting; } public override void Initialize() { #if VIRTUESKY_ADS && VIRTUESKY_ADMOB #if UNITY_IOS // On Android, Unity is paused when displaying interstitial or rewarded video. // This setting makes iOS behave consistently with Android. MobileAds.SetiOSAppPauseOnBackground(true); #endif // When true all events raised by GoogleMobileAds will be raised // on the Unity main thread. The default value is false. // https://developers.google.com/admob/unity/quick-start#raise_ad_events_on_the_unity_main_thread MobileAds.RaiseAdEventsOnUnityMainThread = true; MobileAds.Initialize(initStatus => { App.RunOnMainThread(() => { if (!adSetting.AdmobEnableTestMode) return; var configuration = new RequestConfiguration { TestDeviceIds = adSetting.AdmobDevicesTest }; MobileAds.SetRequestConfiguration(configuration); }); }); FirebaseAnalyticTrackingRevenue.autoTrackAdImpressionAdmob = adSetting.AutoTrackingAdImpressionAdmob; adSetting.AdmobBannerVariable.Init(); adSetting.AdmobInterVariable.Init(); adSetting.AdmobRewardVariable.Init(); adSetting.AdmobRewardInterVariable.Init(); adSetting.AdmobAppOpenVariable.Init(); adSetting.AdmobNativeOverlayVariable.Init(); RegisterAppStateChange(); LoadInterstitial(); LoadRewarded(); LoadRewardedInterstitial(); LoadAppOpen(); LoadBanner(); LoadNativeOverlay(); #endif } #if VIRTUESKY_ADS && VIRTUESKY_ADMOB void RegisterAppStateChange() { GoogleMobileAds.Api.AppStateEventNotifier.AppStateChanged += OnAppStateChanged; } void OnAppStateChanged(GoogleMobileAds.Common.AppState state) { if (state == GoogleMobileAds.Common.AppState.Foreground && adSetting.AdmobAppOpenVariable.autoShow) { if (adSetting.UseAdmob) ShowAppOpen(); } } #endif public override void LoadBanner() { if (adSetting.AdmobBannerVariable == null) return; adSetting.AdmobBannerVariable.Load(); } public override void LoadInterstitial() { if (adSetting.AdmobInterVariable == null) return; if (!adSetting.AdmobInterVariable.IsReady()) adSetting.AdmobInterVariable.Load(); } public override void LoadRewarded() { if (adSetting.AdmobRewardVariable == null) return; if (!adSetting.AdmobRewardVariable.IsReady()) adSetting.AdmobRewardVariable.Load(); } public override void LoadRewardedInterstitial() { if (adSetting.AdmobRewardInterVariable == null) return; if (!adSetting.AdmobRewardInterVariable.IsReady()) adSetting.AdmobRewardInterVariable.Load(); } public override void LoadAppOpen() { if (adSetting.AdmobAppOpenVariable == null) return; if (!adSetting.AdmobAppOpenVariable.IsReady()) adSetting.AdmobAppOpenVariable.Load(); } public override void ShowAppOpen() { if (statusAppOpenFirstIgnore) adSetting.AdmobAppOpenVariable.Show(); statusAppOpenFirstIgnore = true; } public override void LoadNativeOverlay() { if (adSetting.AdmobNativeOverlayVariable == null) return; if (!adSetting.AdmobNativeOverlayVariable.IsReady()) adSetting.AdmobNativeOverlayVariable.Load(); } } } ================================================ FILE: VirtueSky/Advertising/Runtime/Admob/AdmobAdClient.cs.meta ================================================ fileFormatVersion: 2 guid: 9dfd25949deb4dd5b2c3d85ef6e79929 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: ed5ec0bb4ec55df47af0ecc2bd7be5f9, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Advertising/Runtime/Admob/AdmobAdUnitVariable.cs ================================================ using System; using UnityEngine; namespace VirtueSky.Ads { public class AdmobAdUnitVariable : AdUnitVariable { [SerializeField] protected string androidId; [SerializeField] protected string iOSId; [NonSerialized] private string idRuntime = string.Empty; public override bool IsShowing { get; internal set; } public override string Id { get { if (idRuntime == String.Empty) { #if UNITY_ANDROID return androidId; #elif UNITY_IOS return iOSId; #else return string.Empty; #endif } return idRuntime; } } public override AdUnitVariable Show(string placement = null) { ResetChainCallback(); if (!Application.isMobilePlatform || string.IsNullOrEmpty(Id) || AdStatic.IsRemoveAd || !IsReady()) return this; ShowImpl(placement); return this; } public void SetIdRuntime(string unitId) { idRuntime = unitId; } } } ================================================ FILE: VirtueSky/Advertising/Runtime/Admob/AdmobAdUnitVariable.cs.meta ================================================ fileFormatVersion: 2 guid: 87d7f6324d01404eb012e525818f93de timeCreated: 1728634495 ================================================ FILE: VirtueSky/Advertising/Runtime/Admob/AdmodUnitVariable/AdmobAppOpenVariable.cs ================================================ using System; #if VIRTUESKY_ADS && VIRTUESKY_ADMOB using GoogleMobileAds.Api; using VirtueSky.Tracking; #endif using UnityEngine; using VirtueSky.Inspector; using VirtueSky.Misc; namespace VirtueSky.Ads { [Serializable] [EditorIcon("icon_scriptable")] public class AdmobAppOpenVariable : AdmobAdUnitVariable { [Tooltip("Automatically show AppOpenAd when app status is changed")] public bool autoShow = false; [Tooltip("Time between closing the previous full-screen ad and starting to show the app open ad - in seconds")] public float timeBetweenFullScreenAd = 2f; public bool useTestId; #if VIRTUESKY_ADS && VIRTUESKY_ADMOB private AppOpenAd _appOpenAd; #endif private DateTime _expireTime; public override void Init() { if (useTestId) { GetUnitTest(); } #if VIRTUESKY_ADS && VIRTUESKY_ADMOB if (AdStatic.IsRemoveAd || string.IsNullOrEmpty(Id)) return; paidedCallback += AppTracking.TrackRevenue; #endif } public override void Load() { #if VIRTUESKY_ADS && VIRTUESKY_ADMOB if (AdStatic.IsRemoveAd || string.IsNullOrEmpty(Id)) return; Destroy(); AppOpenAd.Load(Id, new AdRequest(), OnAdLoadCallback); #endif } public override bool IsReady() { #if VIRTUESKY_ADS && VIRTUESKY_ADMOB return _appOpenAd != null && _appOpenAd.CanShowAd() && DateTime.Now < _expireTime && (DateTime.Now - AdStatic.AdClosingTime).TotalSeconds > timeBetweenFullScreenAd; #else return false; #endif } protected override void ShowImpl(string placement = null) { #if VIRTUESKY_ADS && VIRTUESKY_ADMOB _appOpenAd.Show(); #endif } public override void Destroy() { #if VIRTUESKY_ADS && VIRTUESKY_ADMOB if (_appOpenAd == null) return; _appOpenAd.Destroy(); _appOpenAd = null; #endif } #if VIRTUESKY_ADS && VIRTUESKY_ADMOB private void OnAdLoadCallback(AppOpenAd ad, LoadAdError error) { // if error is not null, the load request failed. if (error != null || ad == null) { OnAdFailedToLoad(error); return; } _appOpenAd = ad; _appOpenAd.OnAdPaid += OnAdPaided; _appOpenAd.OnAdFullScreenContentClosed += OnAdClosed; _appOpenAd.OnAdFullScreenContentFailed += OnAdFailedToShow; _appOpenAd.OnAdFullScreenContentOpened += OnAdOpening; _appOpenAd.OnAdClicked += OnAdClicked; OnAdLoaded(); // App open ads can be preloaded for up to 4 hours. _expireTime = DateTime.Now + TimeSpan.FromHours(4); } private void OnAdClicked() { Common.CallActionAndClean(ref clickedCallback); OnClickedAdEvent?.Invoke(); } private void OnAdOpening() { AdStatic.waitAppOpenDisplayedAction?.Invoke(); AdStatic.IsShowingAd = true; IsShowing = true; Common.CallActionAndClean(ref displayedCallback); OnDisplayedAdEvent?.Invoke(); } private void OnAdFailedToShow(AdError obj) { Common.CallActionAndClean(ref failedToDisplayCallback); OnFailedToDisplayAdEvent?.Invoke(obj.GetMessage()); } private void OnAdClosed() { AdStatic.waitAppOpenClosedAction?.Invoke(); AdStatic.IsShowingAd = false; IsShowing = false; Common.CallActionAndClean(ref closedCallback); OnClosedAdEvent?.Invoke(); Destroy(); } private void OnAdPaided(AdValue value) { paidedCallback?.Invoke(value.Value / 1000000f, "Admob", Id, "AppOpenAd", AdMediation.Admob.ToString()); } private void OnAdLoaded() { Common.CallActionAndClean(ref loadedCallback); OnLoadAdEvent?.Invoke(); } private void OnAdFailedToLoad(LoadAdError error) { Common.CallActionAndClean(ref failedToLoadCallback); OnFailedToLoadAdEvent?.Invoke(error.GetMessage()); } #endif [ContextMenu("Get Id test")] void GetUnitTest() { #if UNITY_ANDROID androidId = "ca-app-pub-3940256099942544/9257395921"; #elif UNITY_IOS iOSId = "ca-app-pub-3940256099942544/5575463023"; #endif } } } ================================================ FILE: VirtueSky/Advertising/Runtime/Admob/AdmodUnitVariable/AdmobAppOpenVariable.cs.meta ================================================ fileFormatVersion: 2 guid: bcb8d284edcd4713bbddf482061bd612 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: ed5ec0bb4ec55df47af0ecc2bd7be5f9, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Advertising/Runtime/Admob/AdmodUnitVariable/AdmobBannerVariable.cs ================================================ using System; using System.Collections; #if VIRTUESKY_ADS && VIRTUESKY_ADMOB using GoogleMobileAds.Api; using VirtueSky.Tracking; #endif using UnityEngine; using VirtueSky.Core; using VirtueSky.Inspector; using VirtueSky.Misc; namespace VirtueSky.Ads { [Serializable] [EditorIcon("icon_scriptable")] public class AdmobBannerVariable : AdmobAdUnitVariable { public AdsSize size = AdsSize.Adaptive; public AdsPosition position = AdsPosition.Bottom; public bool useCollapsible; public bool useTestId; #if VIRTUESKY_ADS && VIRTUESKY_ADMOB private BannerView _bannerView; #endif private readonly WaitForSeconds _waitBannerReload = new WaitForSeconds(5f); private IEnumerator _reload; private bool _isBannerShowing; private bool _previousBannerShowStatus; public override void Init() { if (useTestId) { GetUnitTest(); } #if VIRTUESKY_ADS && VIRTUESKY_ADMOB if (AdStatic.IsRemoveAd || string.IsNullOrEmpty(Id)) return; paidedCallback += AppTracking.TrackRevenue; #endif } public override void Load() { #if VIRTUESKY_ADS && VIRTUESKY_ADMOB if (AdStatic.IsRemoveAd || string.IsNullOrEmpty(Id)) return; Destroy(); _bannerView = new BannerView(Id, ConvertSize(), ConvertPosition()); _bannerView.OnAdFullScreenContentClosed += OnAdClosed; _bannerView.OnBannerAdLoadFailed += OnAdFailedToLoad; _bannerView.OnBannerAdLoaded += OnAdLoaded; _bannerView.OnAdFullScreenContentOpened += OnAdOpening; _bannerView.OnAdPaid += OnAdPaided; _bannerView.OnAdClicked += OnAdClicked; var adRequest = new AdRequest(); if (useCollapsible) { adRequest.Extras.Add("collapsible", ConvertPlacementCollapsible()); } _bannerView.LoadAd(adRequest); #endif } public bool IsCollapsible() { #if VIRTUESKY_ADS && VIRTUESKY_ADMOB if (_bannerView == null) return false; return _bannerView.IsCollapsible(); #else return false; #endif } void OnWaitAppOpenClosed() { if (_previousBannerShowStatus) { _previousBannerShowStatus = false; Show(); } } void OnWaitAppOpenDisplayed() { _previousBannerShowStatus = _isBannerShowing; if (_isBannerShowing) HideBanner(); } public override bool IsReady() { #if VIRTUESKY_ADS && VIRTUESKY_ADMOB return _bannerView != null; #else return false; #endif } protected override void ShowImpl(string placement = null) { #if VIRTUESKY_ADS && VIRTUESKY_ADMOB _isBannerShowing = true; IsShowing = true; AdStatic.waitAppOpenClosedAction = OnWaitAppOpenClosed; AdStatic.waitAppOpenDisplayedAction = OnWaitAppOpenDisplayed; if (_bannerView == null) { Load(); } _bannerView.Show(); #endif } public override void Destroy() { #if VIRTUESKY_ADS && VIRTUESKY_ADMOB if (_bannerView == null) return; _isBannerShowing = false; IsShowing = false; AdStatic.waitAppOpenClosedAction = null; AdStatic.waitAppOpenDisplayedAction = null; _bannerView.Destroy(); _bannerView = null; #endif } public override void HideBanner() { base.HideBanner(); #if VIRTUESKY_ADS && VIRTUESKY_ADMOB _isBannerShowing = false; IsShowing = false; if (_bannerView != null) _bannerView.Hide(); #endif } #if VIRTUESKY_ADS && VIRTUESKY_ADMOB public AdSize ConvertSize() { switch (size) { case AdsSize.Adaptive: return AdSize.GetCurrentOrientationAnchoredAdaptiveBannerAdSizeWithWidth( AdSize.FullWidth); case AdsSize.MediumRectangle: return AdSize.MediumRectangle; case AdsSize.Leaderboard: return AdSize.Leaderboard; case AdsSize.IABBanner: return AdSize.IABBanner; //case BannerSize.SmartBanner: return AdSize.SmartBanner; default: return AdSize.Banner; } } public AdPosition ConvertPosition() { switch (position) { case AdsPosition.Top: return AdPosition.Top; case AdsPosition.Bottom: return AdPosition.Bottom; case AdsPosition.TopLeft: return AdPosition.TopLeft; case AdsPosition.TopRight: return AdPosition.TopRight; case AdsPosition.BottomLeft: return AdPosition.BottomLeft; case AdsPosition.BottomRight: return AdPosition.BottomRight; default: return AdPosition.Bottom; } } public string ConvertPlacementCollapsible() { if (position == AdsPosition.Top) { return "top"; } else if (position == AdsPosition.Bottom) { return "bottom"; } return "bottom"; } private void OnAdPaided(AdValue value) { paidedCallback?.Invoke(value.Value / 1000000f, "Admob", Id, "BannerAd", AdMediation.Admob.ToString()); } private void OnAdClicked() { Common.CallActionAndClean(ref clickedCallback); OnClickedAdEvent?.Invoke(); } private void OnAdOpening() { Common.CallActionAndClean(ref displayedCallback); OnDisplayedAdEvent?.Invoke(); } private void OnAdLoaded() { Common.CallActionAndClean(ref loadedCallback); OnLoadAdEvent?.Invoke(); } private void OnAdFailedToLoad(LoadAdError error) { Common.CallActionAndClean(ref failedToLoadCallback); OnFailedToLoadAdEvent?.Invoke(error.GetMessage()); if (_reload != null) App.StopCoroutine(_reload); _reload = DelayBannerReload(); App.StartCoroutine(_reload); } private void OnAdClosed() { Common.CallActionAndClean(ref closedCallback); OnClosedAdEvent?.Invoke(); } private IEnumerator DelayBannerReload() { yield return _waitBannerReload; Load(); } #endif [ContextMenu("Get Id test")] void GetUnitTest() { #if UNITY_ANDROID androidId = "ca-app-pub-3940256099942544/6300978111"; #elif UNITY_IOS iOSId = "ca-app-pub-3940256099942544/2934735716"; #endif } } } ================================================ FILE: VirtueSky/Advertising/Runtime/Admob/AdmodUnitVariable/AdmobBannerVariable.cs.meta ================================================ fileFormatVersion: 2 guid: 87ac8fce1cfb4b09805621d419310150 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: ed5ec0bb4ec55df47af0ecc2bd7be5f9, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Advertising/Runtime/Admob/AdmodUnitVariable/AdmobInterVariable.cs ================================================ using System; #if VIRTUESKY_ADS && VIRTUESKY_ADMOB using GoogleMobileAds.Api; using VirtueSky.Tracking; #endif using UnityEngine; using VirtueSky.Inspector; using VirtueSky.Misc; namespace VirtueSky.Ads { [Serializable] [EditorIcon("icon_scriptable")] public class AdmobInterVariable : AdmobAdUnitVariable { public bool useTestId; [NonSerialized] internal Action completedCallback; #if VIRTUESKY_ADS && VIRTUESKY_ADMOB private InterstitialAd _interstitialAd; #endif public override void Init() { if (useTestId) { GetUnitTest(); } #if VIRTUESKY_ADS && VIRTUESKY_ADMOB if (AdStatic.IsRemoveAd || string.IsNullOrEmpty(Id)) return; paidedCallback += AppTracking.TrackRevenue; #endif } public override void Load() { #if VIRTUESKY_ADS && VIRTUESKY_ADMOB if (AdStatic.IsRemoveAd || string.IsNullOrEmpty(Id)) return; Destroy(); InterstitialAd.Load(Id, new AdRequest(), AdLoadCallback); #endif } public override bool IsReady() { #if VIRTUESKY_ADS && VIRTUESKY_ADMOB return _interstitialAd != null && _interstitialAd.CanShowAd(); #else return false; #endif } protected override void ShowImpl(string placement = null) { #if VIRTUESKY_ADS && VIRTUESKY_ADMOB _interstitialAd.Show(); #endif } protected override void ResetChainCallback() { base.ResetChainCallback(); completedCallback = null; } public override void Destroy() { #if VIRTUESKY_ADS && VIRTUESKY_ADMOB if (_interstitialAd == null) return; _interstitialAd.Destroy(); _interstitialAd = null; #endif } #if VIRTUESKY_ADS && VIRTUESKY_ADMOB private void AdLoadCallback(InterstitialAd ad, LoadAdError error) { // if error is not null, the load request failed. if (error != null || ad == null) { OnAdFailedToLoad(error); return; } _interstitialAd = ad; _interstitialAd.OnAdPaid += OnAdPaided; _interstitialAd.OnAdFullScreenContentClosed += OnAdClosed; _interstitialAd.OnAdFullScreenContentFailed += OnAdFailedToShow; _interstitialAd.OnAdFullScreenContentOpened += OnAdOpening; _interstitialAd.OnAdClicked += OnAdClicked; OnAdLoaded(); } private void OnAdClicked() { Common.CallActionAndClean(ref clickedCallback); OnClickedAdEvent?.Invoke(); } private void OnAdOpening() { AdStatic.IsShowingAd = true; IsShowing = true; Common.CallActionAndClean(ref displayedCallback); OnDisplayedAdEvent?.Invoke(); } private void OnAdFailedToShow(AdError error) { Common.CallActionAndClean(ref failedToDisplayCallback); OnFailedToDisplayAdEvent?.Invoke(error.GetMessage()); } private void OnAdClosed() { AdStatic.IsShowingAd = false; IsShowing = false; Common.CallActionAndClean(ref completedCallback); OnClosedAdEvent?.Invoke(); Destroy(); } private void OnAdPaided(AdValue value) { paidedCallback?.Invoke(value.Value / 1000000f, "Admob", Id, "InterstitialAd", AdMediation.Admob.ToString()); } private void OnAdLoaded() { Common.CallActionAndClean(ref loadedCallback); OnLoadAdEvent?.Invoke(); } private void OnAdFailedToLoad(LoadAdError error) { Common.CallActionAndClean(ref failedToLoadCallback); OnFailedToLoadAdEvent?.Invoke(error.GetMessage()); } #endif [ContextMenu("Get Id test")] void GetUnitTest() { #if UNITY_ANDROID androidId = "ca-app-pub-3940256099942544/1033173712"; #elif UNITY_IOS iOSId = "ca-app-pub-3940256099942544/4411468910"; #endif } } } ================================================ FILE: VirtueSky/Advertising/Runtime/Admob/AdmodUnitVariable/AdmobInterVariable.cs.meta ================================================ fileFormatVersion: 2 guid: b04367785ed74ad986055150f5961286 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: ed5ec0bb4ec55df47af0ecc2bd7be5f9, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Advertising/Runtime/Admob/AdmodUnitVariable/AdmobNativeOverlayVariable.cs ================================================ using System; using UnityEngine; using VirtueSky.Inspector; using VirtueSky.Utils; using System.Collections; #if VIRTUESKY_ADS && VIRTUESKY_ADMOB using GoogleMobileAds.Api; #endif using VirtueSky.Core; using VirtueSky.Misc; using VirtueSky.Tracking; namespace VirtueSky.Ads { [Serializable] [EditorIcon("icon_scriptable")] public class AdmobNativeOverlayVariable : AdmobAdUnitVariable { public enum NativeTemplate { Small, Medium } [SerializeField] private bool useTestId; #if VIRTUESKY_ADS && VIRTUESKY_ADMOB [HeaderLine("NativeAd Options", false)] [SerializeField] private AdChoicesPlacement adChoicesPlacement; [SerializeField] private MediaAspectRatio mediaAspectRatio; [SerializeField] private VideoOptions videoOptions; [HeaderLine("NativeAd Style", false)] public NativeTemplate nativeTemplate; public Color mainBackgroundColor = Color.white; public AdsSize adsSize = AdsSize.MediumRectangle; public AdsPosition adsPosition = AdsPosition.Bottom; // public NativeTemplateFontStyle nativeTemplateFontStyle; private NativeOverlayAd _nativeOverlayAd; #endif private readonly WaitForSeconds _waitReload = new WaitForSeconds(5f); private IEnumerator _reload; /// /// Init ads and register callback tracking /// public override void Init() { if (useTestId) { GetUnitTest(); } #if VIRTUESKY_ADS && VIRTUESKY_ADMOB if (AdStatic.IsRemoveAd || string.IsNullOrEmpty(Id)) return; paidedCallback += AppTracking.TrackRevenue; #endif } /// /// Load ads /// public override void Load() { #if VIRTUESKY_ADS && VIRTUESKY_ADMOB if (AdStatic.IsRemoveAd || string.IsNullOrEmpty(Id)) return; if (_nativeOverlayAd != null) { Destroy(); } var adRequest = new AdRequest(); var option = new NativeAdOptions { AdChoicesPlacement = adChoicesPlacement, MediaAspectRatio = mediaAspectRatio, VideoOptions = videoOptions }; NativeOverlayAd.Load(Id, adRequest, option, AdLoadCallback); #endif } public override bool IsReady() { #if VIRTUESKY_ADS && VIRTUESKY_ADMOB return _nativeOverlayAd != null; #else return false; #endif } protected override void ShowImpl(string placement = null) { #if VIRTUESKY_ADS && VIRTUESKY_ADMOB if (_nativeOverlayAd != null) _nativeOverlayAd.Show(); #endif } /// /// destroy native overlay ads /// public override void Destroy() { #if VIRTUESKY_ADS && VIRTUESKY_ADMOB if (_nativeOverlayAd != null) { _nativeOverlayAd.Destroy(); _nativeOverlayAd = null; } #endif } /// /// Hide native overlay ads /// public void Hide() { #if VIRTUESKY_ADS && VIRTUESKY_ADMOB if (_nativeOverlayAd != null) _nativeOverlayAd.Hide(); #endif } /// /// Render native overlay ads default /// public void RenderAd() { #if VIRTUESKY_ADS && VIRTUESKY_ADMOB if (_nativeOverlayAd == null) return; _nativeOverlayAd.RenderTemplate(Style(), ConvertSize(), ConvertPosition(adsPosition)); #endif } /// /// Render native ads according to uiElement, use canvas overlay /// /// RectTransform of uiElement, used to determine position for native overlay ads public void RenderAd(RectTransform uiElement) { #if VIRTUESKY_ADS && VIRTUESKY_ADMOB if (_nativeOverlayAd == null) return; (int admobX, int admobY) = ConvertUiElementPosToNativeAdsPos(uiElement); _nativeOverlayAd.RenderTemplate(Style(), admobX, admobY); #endif } /// /// Render native ads according to uiElement, use canvas overlay /// /// RectTransform of uiElement, used to determine position for native overlay ads /// Custom width for native overlay ads /// Custom height for native overlay ads public void RenderAd(RectTransform uiElement, int width, int height) { #if VIRTUESKY_ADS && VIRTUESKY_ADMOB if (_nativeOverlayAd == null) return; (int admobX, int admobY) = ConvertUiElementPosToNativeAdsPos(uiElement); _nativeOverlayAd.RenderTemplate(Style(), new AdSize(width, height), admobX, admobY); #endif } /// /// Render native ads according to uiElement, use canvas screen-space camera /// Can use position and size of uiElement for native overlay ads /// /// RectTransform of uiElement, used to determine position for native overlay ads /// Camera render uiElement public void RenderAd(RectTransform uiElement, Camera camera, bool useSizeUiElement = true) { #if VIRTUESKY_ADS && VIRTUESKY_ADMOB if (_nativeOverlayAd == null) return; (int admobX, int admobY) = ConvertUiElementPosToNativeAdsPos(uiElement, camera); if (useSizeUiElement) { _nativeOverlayAd?.RenderTemplate(Style(), new AdSize((int)uiElement.rect.width, (int)uiElement.rect.height), admobX, admobY); } else { _nativeOverlayAd?.RenderTemplate(Style(), admobX, admobY); } #endif } /// /// Render native ads according to uiElement, use canvas screen-space camera /// Can use position of uiElement and custom size for native overlay ads /// /// RectTransform of uiElement, used to determine position for native overlay ads /// Camera render uiElement /// Custom width for native overlay ads /// Custom height for native overlay ads public void RenderAd(RectTransform uiElement, Camera camera, int width, int height) { #if VIRTUESKY_ADS && VIRTUESKY_ADMOB if (_nativeOverlayAd == null) return; (int admobX, int admobY) = ConvertUiElementPosToNativeAdsPos(uiElement, camera, width, height); _nativeOverlayAd?.RenderTemplate(Style(), new AdSize(width, height), admobX, admobY); #endif } (int, int) ConvertUiElementPosToNativeAdsPos(RectTransform uiElement, Camera camera, int width, int height) { var worldPosition = uiElement.TransformPoint(uiElement.position); Vector2 screenPosition = camera.WorldToScreenPoint(worldPosition); float dpi = Screen.dpi / 160f; var admobX = (int)((screenPosition.x - width / 2) / dpi); var admobY = (int)(((Screen.height - (int)screenPosition.y) - height / 2) / dpi); return (admobX, admobY); } (int, int) ConvertUiElementPosToNativeAdsPos(RectTransform uiElement, Camera camera) { var worldPosition = uiElement.TransformPoint(uiElement.position); Vector2 screenPosition = camera.WorldToScreenPoint(worldPosition); float dpi = Screen.dpi / 160f; var admobX = (int)((screenPosition.x - (int)uiElement.rect.width / 2) / dpi); var admobY = (int)(((Screen.height - (int)screenPosition.y) - (int)uiElement.rect.height / 2) / dpi); return (admobX, admobY); } (int, int) ConvertUiElementPosToNativeAdsPos(RectTransform uiElement) { var screenPosition = uiElement.ToWorldPosition(); float dpi = Screen.dpi / 160f; var admobX = (int)(screenPosition.x / dpi); var admobY = (int)((Screen.height - (int)screenPosition.y) / dpi); return (admobX, admobY); } public void SetPosition(AdsPosition adsPosition) { #if VIRTUESKY_ADS && VIRTUESKY_ADMOB _nativeOverlayAd.SetTemplatePosition(ConvertPosition(adsPosition)); #endif } public void SetPosition(int x, int y) { #if VIRTUESKY_ADS && VIRTUESKY_ADMOB _nativeOverlayAd.SetTemplatePosition(x, y); #endif } public void SetPosition(RectTransform uiElement) { #if VIRTUESKY_ADS && VIRTUESKY_ADMOB (int x, int y) = ConvertUiElementPosToNativeAdsPos(uiElement); _nativeOverlayAd.SetTemplatePosition(x, y); #endif } public void SetPosition(RectTransform uiElement, Camera camera) { #if VIRTUESKY_ADS && VIRTUESKY_ADMOB (int x, int y) = ConvertUiElementPosToNativeAdsPos(uiElement, camera); _nativeOverlayAd.SetTemplatePosition(x, y); #endif } #if VIRTUESKY_ADS && VIRTUESKY_ADMOB public NativeTemplateStyle Style() { return new NativeTemplateStyle { TemplateId = nativeTemplate.ToString().ToLower(), MainBackgroundColor = mainBackgroundColor, // CallToActionText = new NativeTemplateTextStyle // { // BackgroundColor = Color.green, // TextColor = Color.white, // FontSize = 9, // Style = nativeTemplateFontStyle // } }; } AdPosition ConvertPosition(AdsPosition _adsPosition) { return _adsPosition switch { AdsPosition.Top => AdPosition.Top, AdsPosition.Bottom => AdPosition.Bottom, AdsPosition.TopLeft => AdPosition.TopLeft, AdsPosition.TopRight => AdPosition.TopRight, AdsPosition.BottomLeft => AdPosition.BottomLeft, AdsPosition.BottomRight => AdPosition.BottomRight, _ => AdPosition.Center }; } AdSize ConvertSize() { return adsSize switch { AdsSize.Banner => AdSize.Banner, AdsSize.MediumRectangle => AdSize.MediumRectangle, AdsSize.IABBanner => AdSize.IABBanner, AdsSize.Leaderboard => AdSize.Leaderboard, _ => AdSize.MediumRectangle, }; } private void AdLoadCallback(NativeOverlayAd ad, LoadAdError error) { if (error != null || ad == null) { OnAdFailedToLoad(error); return; } _nativeOverlayAd = ad; _nativeOverlayAd.OnAdPaid += OnAdPaided; _nativeOverlayAd.OnAdClicked += OnAdClicked; _nativeOverlayAd.OnAdFullScreenContentOpened += OnAdOpening; _nativeOverlayAd.OnAdFullScreenContentClosed += OnAdClosed; OnAdLoaded(); } private void OnAdLoaded() { Common.CallActionAndClean(ref loadedCallback); OnLoadAdEvent?.Invoke(); } private void OnAdClosed() { IsShowing = false; Common.CallActionAndClean(ref closedCallback); OnClosedAdEvent?.Invoke(); } private void OnAdOpening() { IsShowing = true; Common.CallActionAndClean(ref displayedCallback); OnDisplayedAdEvent?.Invoke(); } private void OnAdClicked() { Common.CallActionAndClean(ref clickedCallback); OnClickedAdEvent?.Invoke(); } private void OnAdPaided(AdValue value) { paidedCallback?.Invoke(value.Value / 1000000f, "Admob", Id, "NativeOverlayAd", AdMediation.Admob.ToString()); } private void OnAdFailedToLoad(LoadAdError error) { Common.CallActionAndClean(ref failedToLoadCallback); OnFailedToLoadAdEvent?.Invoke(error.GetMessage()); if (_reload != null) App.StopCoroutine(_reload); _reload = DelayReload(); App.StartCoroutine(_reload); } private IEnumerator DelayReload() { yield return _waitReload; Load(); } #endif [ContextMenu("Get Id test")] void GetUnitTest() { #if UNITY_ANDROID androidId = "ca-app-pub-3940256099942544/2247696110"; #elif UNITY_IOS iOSId = "ca-app-pub-3940256099942544/3986624511"; #endif } } } ================================================ FILE: VirtueSky/Advertising/Runtime/Admob/AdmodUnitVariable/AdmobNativeOverlayVariable.cs.meta ================================================ fileFormatVersion: 2 guid: 8b15194a160445d694586481bfdc91cb MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: ed5ec0bb4ec55df47af0ecc2bd7be5f9, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Advertising/Runtime/Admob/AdmodUnitVariable/AdmobRewardInterVariable.cs ================================================ using System; #if VIRTUESKY_ADS && VIRTUESKY_ADMOB using GoogleMobileAds.Api; #endif using UnityEngine; using VirtueSky.Inspector; using VirtueSky.Misc; using VirtueSky.Tracking; namespace VirtueSky.Ads { [Serializable] [EditorIcon("icon_scriptable")] public class AdmobRewardInterVariable : AdmobAdUnitVariable { public bool useTestId; [NonSerialized] internal Action completedCallback; [NonSerialized] internal Action skippedCallback; #if VIRTUESKY_ADS && VIRTUESKY_ADMOB private RewardedInterstitialAd _rewardedInterstitialAd; #endif public override void Init() { if (useTestId) { GetUnitTest(); } #if VIRTUESKY_ADS && VIRTUESKY_ADMOB if (string.IsNullOrEmpty(Id)) return; paidedCallback += AppTracking.TrackRevenue; #endif } public bool IsEarnRewarded { get; private set; } public override void Load() { #if VIRTUESKY_ADS && VIRTUESKY_ADMOB if (string.IsNullOrEmpty(Id)) return; Destroy(); RewardedInterstitialAd.Load(Id, new AdRequest(), OnAdLoadCallback); #endif } public override bool IsReady() { #if VIRTUESKY_ADS && VIRTUESKY_ADMOB return _rewardedInterstitialAd != null && _rewardedInterstitialAd.CanShowAd(); #else return false; #endif } protected override void ShowImpl(string placement = null) { #if VIRTUESKY_ADS && VIRTUESKY_ADMOB _rewardedInterstitialAd.Show(UserEarnedRewardCallback); #endif } protected override void ResetChainCallback() { base.ResetChainCallback(); completedCallback = null; skippedCallback = null; } public override AdUnitVariable Show(string placement = null) { ResetChainCallback(); if (!UnityEngine.Application.isMobilePlatform || string.IsNullOrEmpty(Id) || !IsReady()) return this; ShowImpl(placement); return this; } public override void Destroy() { #if VIRTUESKY_ADS && VIRTUESKY_ADMOB if (_rewardedInterstitialAd == null) return; _rewardedInterstitialAd.Destroy(); _rewardedInterstitialAd = null; IsEarnRewarded = false; #endif } #if VIRTUESKY_ADS && VIRTUESKY_ADMOB private void OnAdLoadCallback(RewardedInterstitialAd ad, LoadAdError error) { // if error is not null, the load request failed. if (error != null || ad == null) { OnAdFailedToLoad(error); return; } _rewardedInterstitialAd = ad; _rewardedInterstitialAd.OnAdFullScreenContentClosed += OnAdClosed; _rewardedInterstitialAd.OnAdFullScreenContentOpened += OnAdOpening; _rewardedInterstitialAd.OnAdFullScreenContentFailed += OnAdFailedToShow; _rewardedInterstitialAd.OnAdPaid += OnAdPaided; _rewardedInterstitialAd.OnAdClicked += OnAdClicked; OnAdLoaded(); } private void OnAdClicked() { Common.CallActionAndClean(ref clickedCallback); OnClickedAdEvent?.Invoke(); } private void OnAdFailedToLoad(LoadAdError error) { Common.CallActionAndClean(ref failedToLoadCallback); OnFailedToLoadAdEvent?.Invoke(error.GetMessage()); } private void OnAdLoaded() { Common.CallActionAndClean(ref loadedCallback); OnLoadAdEvent?.Invoke(); } private void OnAdPaided(AdValue value) { paidedCallback?.Invoke(value.Value / 1000000f, "Admob", Id, "RewardedInterstitialAd", AdMediation.Admob.ToString()); } private void OnAdFailedToShow(AdError error) { Common.CallActionAndClean(ref failedToDisplayCallback); OnFailedToDisplayAdEvent?.Invoke(error.GetMessage()); } private void OnAdOpening() { AdStatic.IsShowingAd = true; IsShowing = true; Common.CallActionAndClean(ref displayedCallback); OnDisplayedAdEvent?.Invoke(); } private void OnAdClosed() { AdStatic.IsShowingAd = false; IsShowing = false; Common.CallActionAndClean(ref closedCallback); OnClosedAdEvent?.Invoke(); if (IsEarnRewarded) { Common.CallActionAndClean(ref completedCallback); _rewardedInterstitialAd.Destroy(); return; } Common.CallActionAndClean(ref skippedCallback); _rewardedInterstitialAd.Destroy(); } private void UserEarnedRewardCallback(Reward reward) { IsEarnRewarded = true; } #endif [ContextMenu("Get Id test")] void GetUnitTest() { #if UNITY_ANDROID androidId = "ca-app-pub-3940256099942544/5354046379"; #elif UNITY_IOS iOSId = "ca-app-pub-3940256099942544/6978759866"; #endif } } } ================================================ FILE: VirtueSky/Advertising/Runtime/Admob/AdmodUnitVariable/AdmobRewardInterVariable.cs.meta ================================================ fileFormatVersion: 2 guid: ddd2127be5434974aa775c9d809bc25f MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: ed5ec0bb4ec55df47af0ecc2bd7be5f9, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Advertising/Runtime/Admob/AdmodUnitVariable/AdmobRewardVariable.cs ================================================ using System; #if VIRTUESKY_ADS && VIRTUESKY_ADMOB using GoogleMobileAds.Api; #endif using UnityEngine; using VirtueSky.Inspector; using VirtueSky.Misc; using VirtueSky.Tracking; namespace VirtueSky.Ads { [Serializable] [EditorIcon("icon_scriptable")] public class AdmobRewardVariable : AdmobAdUnitVariable { public bool useTestId; [NonSerialized] internal Action completedCallback; [NonSerialized] internal Action skippedCallback; #if VIRTUESKY_ADS && VIRTUESKY_ADMOB private RewardedAd _rewardedAd; #endif public override void Init() { if (useTestId) { GetUnitTest(); } #if VIRTUESKY_ADS && VIRTUESKY_ADMOB if (string.IsNullOrEmpty(Id)) return; paidedCallback += AppTracking.TrackRevenue; #endif } public bool IsEarnRewarded { get; private set; } public override void Load() { #if VIRTUESKY_ADS && VIRTUESKY_ADMOB if (string.IsNullOrEmpty(Id)) return; Destroy(); RewardedAd.Load(Id, new AdRequest(), AdLoadCallback); #endif } public override bool IsReady() { #if VIRTUESKY_ADS && VIRTUESKY_ADMOB return _rewardedAd != null && _rewardedAd.CanShowAd(); #else return false; #endif } protected override void ShowImpl(string placement = null) { #if VIRTUESKY_ADS && VIRTUESKY_ADMOB _rewardedAd.Show(UserRewardEarnedCallback); #endif } public override AdUnitVariable Show(string placement = null) { ResetChainCallback(); if (!UnityEngine.Application.isMobilePlatform || string.IsNullOrEmpty(Id) || !IsReady()) return this; ShowImpl(placement); return this; } protected override void ResetChainCallback() { base.ResetChainCallback(); completedCallback = null; skippedCallback = null; } public override void Destroy() { #if VIRTUESKY_ADS && VIRTUESKY_ADMOB if (_rewardedAd == null) return; _rewardedAd.Destroy(); _rewardedAd = null; IsEarnRewarded = false; #endif } #if VIRTUESKY_ADS && VIRTUESKY_ADMOB private void AdLoadCallback(RewardedAd ad, LoadAdError error) { // if error is not null, the load request failed. if (error != null || ad == null) { OnAdFailedToLoad(error); return; } _rewardedAd = ad; _rewardedAd.OnAdFullScreenContentClosed += OnAdClosed; _rewardedAd.OnAdFullScreenContentFailed += OnAdFailedToShow; _rewardedAd.OnAdFullScreenContentOpened += OnAdOpening; _rewardedAd.OnAdPaid += OnAdPaided; _rewardedAd.OnAdClicked += OnAdClicked; OnAdLoaded(); } private void OnAdClicked() { Common.CallActionAndClean(ref clickedCallback); OnClickedAdEvent?.Invoke(); } private void OnAdPaided(AdValue value) { paidedCallback?.Invoke(value.Value / 1000000f, "Admob", Id, "RewardedAd", AdMediation.Admob.ToString()); } private void OnAdOpening() { AdStatic.IsShowingAd = true; IsShowing = true; Common.CallActionAndClean(ref displayedCallback); OnDisplayedAdEvent?.Invoke(); } private void OnAdFailedToShow(AdError obj) { Common.CallActionAndClean(ref failedToDisplayCallback); OnFailedToDisplayAdEvent?.Invoke(obj.GetMessage()); } private void OnAdClosed() { AdStatic.IsShowingAd = false; IsShowing = false; Common.CallActionAndClean(ref closedCallback); OnClosedAdEvent?.Invoke(); if (IsEarnRewarded) { Common.CallActionAndClean(ref completedCallback); Destroy(); return; } Common.CallActionAndClean(ref skippedCallback); Destroy(); } private void OnAdLoaded() { Common.CallActionAndClean(ref loadedCallback); OnLoadAdEvent?.Invoke(); } private void OnAdFailedToLoad(LoadAdError error) { Common.CallActionAndClean(ref failedToLoadCallback); OnFailedToLoadAdEvent?.Invoke(error.GetMessage()); } private void UserRewardEarnedCallback(Reward reward) { IsEarnRewarded = true; } #endif [ContextMenu("Get Id test")] void GetUnitTest() { #if UNITY_ANDROID androidId = "ca-app-pub-3940256099942544/5224354917"; #elif UNITY_IOS iOSId = "ca-app-pub-3940256099942544/1712485313"; #endif } } } ================================================ FILE: VirtueSky/Advertising/Runtime/Admob/AdmodUnitVariable/AdmobRewardVariable.cs.meta ================================================ fileFormatVersion: 2 guid: 0199f7cf7b5f44cfa63f780b9ff50857 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: ed5ec0bb4ec55df47af0ecc2bd7be5f9, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Advertising/Runtime/Admob/AdmodUnitVariable.meta ================================================ fileFormatVersion: 2 guid: 5a8d9ff9a56c4478887d3a9190da2563 timeCreated: 1695462336 ================================================ FILE: VirtueSky/Advertising/Runtime/Admob.meta ================================================ fileFormatVersion: 2 guid: 488c040c267923f4e91f3c963c4e9536 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Advertising/Runtime/General/AdClient.cs ================================================ using VirtueSky.Tracking; namespace VirtueSky.Ads { public abstract class AdClient { protected AdSetting adSetting; protected bool statusAppOpenFirstIgnore; // public AdClient(AdSetting _adSetting) // { // adSetting = _adSetting; // } public void SetupAdSetting(AdSetting _adSetting) { this.adSetting = _adSetting; } public abstract void Initialize(); public abstract void LoadBanner(); public abstract void LoadInterstitial(); public abstract void LoadRewarded(); public abstract void LoadRewardedInterstitial(); public abstract void LoadAppOpen(); public abstract void ShowAppOpen(); //Currently, native overlay ads is only available for admob. public abstract void LoadNativeOverlay(); } } ================================================ FILE: VirtueSky/Advertising/Runtime/General/AdClient.cs.meta ================================================ fileFormatVersion: 2 guid: 7af305bf9c13403badeef5393ca8283a timeCreated: 1695566887 ================================================ FILE: VirtueSky/Advertising/Runtime/General/AdInfo.cs ================================================ namespace VirtueSky.Ads { public class AdsInfo { public string AdUnitId { get; private set; } public string AdFormat { get; private set; } public string Placement { get; private set; } public string AdNetwork { get; private set; } public double Revenue { get; private set; } public string AdMediation { get; private set; } public string AuctionId { get; private set; } #if VIRTUESKY_APPLOVIN public AdsInfo(MaxSdkBase.AdInfo info) { AdUnitId = info.AdUnitIdentifier; AdFormat = info.AdFormat; Placement = info.Placement; AdNetwork = info.NetworkName; Revenue = info.Revenue; AdMediation = Ads.AdMediation.AppLovin.ToString(); AuctionId = ""; } #endif #if VIRTUESKY_LEVELPLAY public AdsInfo(Unity.Services.LevelPlay.LevelPlayAdInfo info) { AdUnitId = info.AdUnitId; AdFormat = info.AdFormat; Placement = info.PlacementName; AdNetwork = info.AdNetwork; Revenue = (double)info.Revenue; AdMediation = Ads.AdMediation.LevelPlay.ToString(); AuctionId = info.AuctionId; } #endif public AdsInfo(string adUnitId, string adFormat, string placement, string adNetwork, double revenue, string adMediation, string auctionId) { AdUnitId = adUnitId; AdFormat = adFormat; Placement = placement; AdNetwork = adNetwork; Revenue = revenue; AdMediation = adMediation; AuctionId = auctionId; } } public class AdsError { public int ErrorCode { get; private set; } public string ErrorMessage { get; private set; } #if VIRTUESKY_APPLOVIN public AdsError(MaxSdkBase.ErrorInfo info) { ErrorCode = (int)info.Code; ErrorMessage = info.Message; } #endif #if VIRTUESKY_LEVELPLAY public AdsError(Unity.Services.LevelPlay.LevelPlayAdError adError) { ErrorCode = adError.ErrorCode; ErrorMessage = adError.ErrorMessage; } #endif #if VIRTUESKY_ADMOB public AdsError(GoogleMobileAds.Api.AdError adError) { ErrorCode = adError.GetCode(); ErrorMessage = adError.GetMessage(); } #endif public AdsError(int errorCode, string errorMessage) { ErrorCode = errorCode; ErrorMessage = errorMessage; } } } ================================================ FILE: VirtueSky/Advertising/Runtime/General/AdInfo.cs.meta ================================================ fileFormatVersion: 2 guid: 12c07896615a460a871b51f30257302f timeCreated: 1776757990 ================================================ FILE: VirtueSky/Advertising/Runtime/General/AdSetting.cs ================================================ using System.Collections.Generic; using UnityEngine; using UnityEngine.Serialization; using VirtueSky.Inspector; #if UNITY_EDITOR using VirtueSky.UtilsEditor; #endif namespace VirtueSky.Ads { [EditorIcon("icon_scriptable")] public class AdSetting : ScriptableObject { [Range(5, 100), SerializeField] private float adCheckingInterval = 8f; [Range(5, 100), SerializeField] private float adLoadingInterval = 15f; [SerializeField] private bool useAppLovin = true; [SerializeField] private bool useAdmob; [SerializeField] private bool useLevelPlay; [SerializeField] private bool enableTrackAdRevenue = true; [Tooltip("Install google-mobile-ads sdk to use GDPR"), SerializeField] private bool enableGDPR; [SerializeField] private bool enableGDPRTestMode; public float AdCheckingInterval => adCheckingInterval; public float AdLoadingInterval => adLoadingInterval; public bool UseAppLovin => useAppLovin; public bool UseAdmob => useAdmob; public bool UseLevelPlay => useLevelPlay; public bool EnableTrackAdRevenue => enableTrackAdRevenue; public bool EnableGDPR => enableGDPR; public bool EnableGDPRTestMode => enableGDPRTestMode; #region AppLovin [TextArea, SerializeField] private string sdkKey; [SerializeField] private MaxBannerVariable maxBannerVariable; [SerializeField] private MaxInterVariable maxInterVariable; [SerializeField] private MaxRewardVariable maxRewardVariable; [SerializeField] private MaxAppOpenVariable maxAppOpenVariable; public string SdkKey => sdkKey; public MaxBannerVariable MaxBannerVariable => maxBannerVariable; public MaxInterVariable MaxInterVariable => maxInterVariable; public MaxRewardVariable MaxRewardVariable => maxRewardVariable; public MaxAppOpenVariable MaxAppOpenVariable => maxAppOpenVariable; #endregion #region Admob // [HeaderLine("Admob")] [SerializeField] private AdmobBannerVariable admobBannerVariable; [SerializeField] private AdmobInterVariable admobInterVariable; [SerializeField] private AdmobRewardVariable admobRewardVariable; [SerializeField] private AdmobRewardInterVariable admobRewardInterVariable; [SerializeField] private AdmobAppOpenVariable admobAppOpenVariable; [SerializeField] private AdmobNativeOverlayVariable admobNativeOverlayVariable; [Tooltip( "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."), SerializeField] private bool autoTrackingAdImpressionAdmob = true; [SerializeField] private bool admobEnableTestMode; [SerializeField] private List admobDevicesTest; public AdmobBannerVariable AdmobBannerVariable => admobBannerVariable; public AdmobInterVariable AdmobInterVariable => admobInterVariable; public AdmobRewardVariable AdmobRewardVariable => admobRewardVariable; public AdmobRewardInterVariable AdmobRewardInterVariable => admobRewardInterVariable; public AdmobAppOpenVariable AdmobAppOpenVariable => admobAppOpenVariable; public AdmobNativeOverlayVariable AdmobNativeOverlayVariable => admobNativeOverlayVariable; public bool AdmobEnableTestMode => admobEnableTestMode; public bool AutoTrackingAdImpressionAdmob => autoTrackingAdImpressionAdmob; public List AdmobDevicesTest => admobDevicesTest; #endregion #region LevelPlay [SerializeField] private string androidAppKey; [SerializeField] private string iOSAppKey; [SerializeField] private bool useTestAppKey; [SerializeField] private LevelPlayBannerVariable levelPlayBannerVariable; [SerializeField] private LevelPlayInterVariable levelPlayInterVariable; [SerializeField] private LevelPlayRewardVariable levelPlayRewardVariable; public string AndroidAppKey { get => androidAppKey; set => androidAppKey = value; } public string IosAppKey { get => iOSAppKey; set => iOSAppKey = value; } public string AppKey { get { #if UNITY_ANDROID return androidAppKey; #elif UNITY_IOS return iOSAppKey; #else return string.Empty; #endif } set { #if UNITY_ANDROID androidAppKey = value; #elif UNITY_IOS iOSAppKey = value; #endif } } public bool UseTestAppKey => useTestAppKey; public LevelPlayBannerVariable LevelPlayBannerVariable => levelPlayBannerVariable; public LevelPlayInterVariable LevelPlayInterVariable => levelPlayInterVariable; public LevelPlayRewardVariable LevelPlayRewardVariable => levelPlayRewardVariable; #endregion } public enum AdMediation { AppLovin, Admob, LevelPlay } public enum AdsPosition { Top = 1, Bottom = 0, TopLeft = 2, TopRight = 3, BottomLeft = 4, BottomRight = 5, Center = 6, } public enum AdsSize { Banner = 0, // 320x50 Adaptive = 5, // full width MediumRectangle = 1, // 300x250 IABBanner = 2, // 468x60 Leaderboard = 3, // 728x90 // SmartBanner = 4, } } ================================================ FILE: VirtueSky/Advertising/Runtime/General/AdSetting.cs.meta ================================================ fileFormatVersion: 2 guid: 4faf330974234e808669c796dc78cdee MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: ed5ec0bb4ec55df47af0ecc2bd7be5f9, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Advertising/Runtime/General/AdStatic.cs ================================================ using System; using UnityEngine; using VirtueSky.DataStorage; namespace VirtueSky.Ads { public static class AdStatic { public static bool IsRemoveAd { get => GameData.Get($"{Application.identifier}_removeads", false); set => GameData.Set($"{Application.identifier}_removeads", value); } public static DateTime AdClosingTime { get; internal set; } private static bool isShowingAd; public static bool IsShowingAd { get => isShowingAd; internal set { isShowingAd = value; if (!value) { AdClosingTime = DateTime.Now; } } } internal static Action waitAppOpenDisplayedAction; internal static Action waitAppOpenClosedAction; public static AdUnitVariable OnDisplayed(this AdUnitVariable unit, Action onDisplayed) { unit.displayedCallback = onDisplayed; return unit; } public static AdUnitVariable OnClosed(this AdUnitVariable unit, Action onClosed) { unit.closedCallback = onClosed; return unit; } public static AdUnitVariable OnLoaded(this AdUnitVariable unit, Action onLoaded) { unit.loadedCallback = onLoaded; return unit; } public static AdUnitVariable OnFailedToLoad(this AdUnitVariable unit, Action onFailedToLoad) { unit.failedToLoadCallback = onFailedToLoad; return unit; } public static AdUnitVariable OnFailedToDisplay(this AdUnitVariable unit, Action onFailedToDisplay) { unit.failedToDisplayCallback = onFailedToDisplay; return unit; } public static AdUnitVariable OnClicked(this AdUnitVariable unit, Action onClicked) { unit.clickedCallback = onClicked; return unit; } public static AdUnitVariable OnCompleted(this AdUnitVariable unit, Action onCompleted) { if (!Application.isMobilePlatform) { onCompleted?.Invoke(); } switch (unit) { case AdmobInterVariable admobInter: admobInter.completedCallback = onCompleted; return unit; case AdmobRewardVariable admobReward: admobReward.completedCallback = onCompleted; return unit; case AdmobRewardInterVariable admobRewardInter: admobRewardInter.completedCallback = onCompleted; return unit; case MaxInterVariable maxInter: maxInter.completedCallback = onCompleted; return unit; case MaxRewardVariable maxReward: maxReward.completedCallback = onCompleted; return unit; case LevelPlayInterVariable ironSourceInterVariable: ironSourceInterVariable.completedCallback = onCompleted; return unit; case LevelPlayRewardVariable ironSourceRewardVariable: ironSourceRewardVariable.completedCallback = onCompleted; return unit; } return unit; } public static AdUnitVariable OnSkipped(this AdUnitVariable unit, Action onSkipped) { switch (unit) { case AdmobRewardVariable admobReward: admobReward.skippedCallback = onSkipped; return unit; case AdmobRewardInterVariable admobRewardInter: admobRewardInter.skippedCallback = onSkipped; return unit; case MaxRewardVariable maxReward: maxReward.skippedCallback = onSkipped; return unit; case LevelPlayRewardVariable ironSourceRewardVariable: ironSourceRewardVariable.skippedCallback = onSkipped; return unit; } return unit; } } } ================================================ FILE: VirtueSky/Advertising/Runtime/General/AdStatic.cs.meta ================================================ fileFormatVersion: 2 guid: 4132cc5be9fa4959a8bafd62a51bb7ca timeCreated: 1695460884 ================================================ FILE: VirtueSky/Advertising/Runtime/General/AdUnitVariable.cs ================================================ using System; using UnityEngine; namespace VirtueSky.Ads { public abstract class AdUnitVariable : ScriptableObject, IAdUnit { [NonSerialized] internal Action loadedCallback; [NonSerialized] internal Action failedToLoadCallback; [NonSerialized] internal Action displayedCallback; [NonSerialized] internal Action failedToDisplayCallback; [NonSerialized] internal Action closedCallback; [NonSerialized] internal Action clickedCallback; [NonSerialized] public Action paidedCallback; public Action OnLoadAdEvent; public Action OnFailedToLoadAdEvent; public Action OnDisplayedAdEvent; public Action OnFailedToDisplayAdEvent; public Action OnClosedAdEvent; public Action OnClickedAdEvent; public abstract bool IsShowing { get; internal set; } public virtual string Id { get => ""; } protected virtual void ShowImpl(string placement = null) { } protected virtual void ResetChainCallback() { loadedCallback = null; failedToDisplayCallback = null; failedToLoadCallback = null; closedCallback = null; } public virtual void HideBanner() { } public abstract AdUnitVariable Show(string placement = null); public virtual void Init() { } public virtual void Load() { } public virtual bool IsReady() { return false; } public virtual void Destroy() { } } } ================================================ FILE: VirtueSky/Advertising/Runtime/General/AdUnitVariable.cs.meta ================================================ fileFormatVersion: 2 guid: 0a0b123368074cd1a359dea0f1ef9233 timeCreated: 1695460627 ================================================ FILE: VirtueSky/Advertising/Runtime/General/Advertising.cs ================================================ using System; using System.Collections; using System.Collections.Generic; #if VIRTUESKY_ADMOB using GoogleMobileAds.Api; using GoogleMobileAds.Ump.Api; #endif #if UNITY_IOS using Unity.Advertisement.IosSupport; #endif using UnityEngine; using UnityEngine.Serialization; #if UNITY_EDITOR using VirtueSky.UtilsEditor; #endif using VirtueSky.Events; using VirtueSky.Inspector; using VirtueSky.Misc; using VirtueSky.Tracking; using VirtueSky.Utils; namespace VirtueSky.Ads { [EditorIcon("icon_controller"), HideMonoScript] public class Advertising : MonoBehaviour { [Space] [SerializeField] private bool dontDestroyOnLoad = false; [Tooltip("Require"), SerializeField] private AdSetting adSetting; [Tooltip("Allows nulls"), SerializeField] private BooleanEvent changePreventDisplayAppOpenEvent; #if VIRTUESKY_ADMOB [Space] [HeaderLine("Admob GDPR")] [Tooltip("Allows nulls"), SerializeField] private EventNoParam callShowAgainGDPREvent; #endif private IEnumerator autoLoadAdCoroutine; private float _lastTimeLoadInterstitialAdTimestamp = DEFAULT_TIMESTAMP; private float _lastTimeLoadRewardedTimestamp = DEFAULT_TIMESTAMP; private float _lastTimeLoadRewardedInterstitialTimestamp = DEFAULT_TIMESTAMP; private float _lastTimeLoadAppOpenTimestamp = DEFAULT_TIMESTAMP; private const float DEFAULT_TIMESTAMP = -1000; // private AdClient currentAdClient; private AdClient maxAdClient; private AdClient admobAdClient; private AdClient ironSourceAdClient; private void Awake() { if (dontDestroyOnLoad) { DontDestroyOnLoad(this.gameObject); } } private void OnEnable() { #if VIRTUESKY_ADMOB if (callShowAgainGDPREvent != null) { callShowAgainGDPREvent.AddListener(ShowPrivacyOptionsForm); } #endif } private void OnDisable() { #if VIRTUESKY_ADMOB if (callShowAgainGDPREvent != null) { callShowAgainGDPREvent.RemoveListener(ShowPrivacyOptionsForm); } #endif } private void Start() { if (changePreventDisplayAppOpenEvent != null) changePreventDisplayAppOpenEvent.AddListener(OnChangePreventDisplayOpenAd); if (adSetting.EnableGDPR) { #if VIRTUESKY_ADMOB #if UNITY_IOS if (ATTrackingStatusBinding.GetAuthorizationTrackingStatus() == ATTrackingStatusBinding.AuthorizationTrackingStatus.AUTHORIZED) { InitGdpr(); } else { InitAdClient(); } #else InitGdpr(); #endif #endif } else { InitAdClient(); } } void InitAdClient() { AppTracking.Init(adSetting.EnableTrackAdRevenue); if (adSetting.UseAppLovin) { maxAdClient = new MaxAdClient(adSetting); maxAdClient.Initialize(); Debug.Log($"Use: {maxAdClient}".SetColor(CustomColor.Cyan)); } if (adSetting.UseAdmob) { admobAdClient = new AdmobAdClient(adSetting); admobAdClient.Initialize(); Debug.Log($"Use: {admobAdClient}".SetColor(CustomColor.Cyan)); } if (adSetting.UseLevelPlay) { ironSourceAdClient = new LevelPlayAdClient(adSetting); ironSourceAdClient.Initialize(); Debug.Log($"Use: {ironSourceAdClient}".SetColor(CustomColor.Cyan)); } InitAutoLoadAds(); } private void InitAutoLoadAds() { if (autoLoadAdCoroutine != null) StopCoroutine(autoLoadAdCoroutine); autoLoadAdCoroutine = IeAutoLoadAll(); StartCoroutine(autoLoadAdCoroutine); } private void OnChangePreventDisplayOpenAd(bool state) { AdStatic.IsShowingAd = state; } IEnumerator IeAutoLoadAll(float delay = 0) { if (delay > 0) yield return new WaitForSeconds(delay); while (true) { AutoLoadInterAds(); AutoLoadRewardAds(); AutoLoadRewardInterAds(); AutoLoadAppOpenAds(); yield return new WaitForSeconds(adSetting.AdCheckingInterval); } } #region Func Load Ads void AutoLoadInterAds() { if (Time.realtimeSinceStartup - _lastTimeLoadInterstitialAdTimestamp < adSetting.AdLoadingInterval) return; if (adSetting.UseAppLovin) maxAdClient.LoadInterstitial(); if (adSetting.UseAdmob) admobAdClient.LoadInterstitial(); if (adSetting.UseLevelPlay) ironSourceAdClient.LoadInterstitial(); _lastTimeLoadInterstitialAdTimestamp = Time.realtimeSinceStartup; } void AutoLoadRewardAds() { if (Time.realtimeSinceStartup - _lastTimeLoadRewardedTimestamp < adSetting.AdLoadingInterval) return; if (adSetting.UseAppLovin) maxAdClient.LoadRewarded(); if (adSetting.UseAdmob) admobAdClient.LoadRewarded(); if (adSetting.UseLevelPlay) ironSourceAdClient.LoadRewarded(); _lastTimeLoadRewardedTimestamp = Time.realtimeSinceStartup; } void AutoLoadRewardInterAds() { if (Time.realtimeSinceStartup - _lastTimeLoadRewardedInterstitialTimestamp < adSetting.AdLoadingInterval) return; if (adSetting.UseAppLovin) maxAdClient.LoadRewardedInterstitial(); if (adSetting.UseAdmob) admobAdClient.LoadRewardedInterstitial(); if (adSetting.UseLevelPlay) ironSourceAdClient.LoadRewardedInterstitial(); _lastTimeLoadRewardedInterstitialTimestamp = Time.realtimeSinceStartup; } void AutoLoadAppOpenAds() { if (Time.realtimeSinceStartup - _lastTimeLoadAppOpenTimestamp < adSetting.AdLoadingInterval) return; if (adSetting.UseAppLovin) maxAdClient.LoadAppOpen(); if (adSetting.UseAdmob) admobAdClient.LoadAppOpen(); if (adSetting.UseLevelPlay) ironSourceAdClient.LoadAppOpen(); _lastTimeLoadAppOpenTimestamp = Time.realtimeSinceStartup; } #endregion #region Admob GDPR #if VIRTUESKY_ADMOB private void InitGdpr() { #if UNITY_EDITOR InitAdClient(); #else string deviceID = SystemInfo.deviceUniqueIdentifier; string deviceIDUpperCase = deviceID.ToUpper(); Debug.Log("TestDeviceHashedId = " + deviceIDUpperCase); ConsentRequestParameters request = new ConsentRequestParameters { TagForUnderAgeOfConsent = false }; if (adSetting.EnableGDPRTestMode) { List listDeviceIdTestMode = new List(); listDeviceIdTestMode.Add(deviceIDUpperCase); request.ConsentDebugSettings = new ConsentDebugSettings { DebugGeography = DebugGeography.EEA, TestDeviceHashedIds = listDeviceIdTestMode }; } ConsentInformation.Update(request, OnConsentInfoUpdated); #endif } private void OnConsentInfoUpdated(FormError consentError) { if (consentError != null) { Debug.Log("error consentError = " + consentError); return; } ConsentForm.LoadAndShowConsentFormIfRequired((FormError formError) => { if (formError != null) { Debug.Log("error consentError = " + consentError); return; } Debug.Log("ConsentStatus = " + ConsentInformation.ConsentStatus.ToString()); Debug.Log("CanRequestAds = " + ConsentInformation.CanRequestAds()); if (ConsentInformation.CanRequestAds()) { MobileAds.RaiseAdEventsOnUnityMainThread = true; InitAdClient(); } } ); } public void LoadAndShowConsentForm() { Debug.Log("LoadAndShowConsentForm Start!"); ConsentForm.Load((consentForm, loadError) => { if (loadError != null) { Debug.Log("error loadError = " + loadError); return; } consentForm.Show(showError => { if (showError != null) { Debug.Log("error showError = " + showError); return; } }); }); } private void ShowPrivacyOptionsForm() { Debug.Log("Showing privacy options form."); ConsentForm.ShowPrivacyOptionsForm((FormError showError) => { if (showError != null) { Debug.LogError("Error showing privacy options form with error: " + showError.Message); } }); } #endif #endregion #if UNITY_EDITOR private void Reset() { adSetting = CreateAsset.CreateAndGetScriptableAsset("/Ads/Setting"); } #endif } } ================================================ FILE: VirtueSky/Advertising/Runtime/General/Advertising.cs.meta ================================================ fileFormatVersion: 2 guid: e380b752cb6c40aaace317083692044f MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 1c63e3b6583d6b54a8de6efcd2a86725, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Advertising/Runtime/General/IAdUnit.cs ================================================ namespace VirtueSky.Ads { public interface IAdUnit { public void Init(); public void Load(); public bool IsReady(); public void Destroy(); } } ================================================ FILE: VirtueSky/Advertising/Runtime/General/IAdUnit.cs.meta ================================================ fileFormatVersion: 2 guid: 5114c7ef942a40ff9e7dbf458d6ed339 timeCreated: 1728631990 ================================================ FILE: VirtueSky/Advertising/Runtime/General.meta ================================================ fileFormatVersion: 2 guid: f3d6f74e978547a43947efa49ed48e87 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Advertising/Runtime/LevelPlay/LevelPlayAdClient.cs ================================================ #if VIRTUESKY_ADS && VIRTUESKY_LEVELPLAY using Unity.Services.LevelPlay; #endif using VirtueSky.Core; using VirtueSky.Tracking; namespace VirtueSky.Ads { public sealed class LevelPlayAdClient : AdClient { public LevelPlayAdClient(AdSetting _adSetting) { adSetting = _adSetting; } public bool SdkInitializationCompleted { get; private set; } public override void Initialize() { SdkInitializationCompleted = false; if (adSetting.UseTestAppKey) { adSetting.AndroidAppKey = "85460dcd"; adSetting.IosAppKey = "8545d445"; } #if VIRTUESKY_ADS && VIRTUESKY_LEVELPLAY App.AddPauseCallback(OnAppStateChange); LevelPlay.OnInitSuccess += SdkInitializationCompletedEvent; LevelPlay.OnImpressionDataReady += ImpressionDataReadyEvent; adSetting.LevelPlayBannerVariable.Init(); adSetting.LevelPlayInterVariable.Init(); adSetting.LevelPlayRewardVariable.Init(); LevelPlay.ValidateIntegration(); LevelPlay.Init(adSetting.AppKey); #endif } #if VIRTUESKY_ADS && VIRTUESKY_LEVELPLAY private void ImpressionDataReadyEvent(LevelPlayImpressionData impressionData) { if (impressionData.Revenue != null) { AppTracking.TrackRevenue((double)impressionData.Revenue, impressionData.AdNetwork, impressionData.MediationAdUnitId, impressionData.AdFormat, AdMediation.LevelPlay.ToString()); } } private void OnAppStateChange(bool pauseStatus) { LevelPlay.SetPauseGame(pauseStatus); } void SdkInitializationCompletedEvent(LevelPlayConfiguration config) { SdkInitializationCompleted = true; LoadInterstitial(); LoadRewarded(); LoadBanner(); } #endif public override void LoadBanner() { if (adSetting.LevelPlayBannerVariable == null) return; adSetting.LevelPlayBannerVariable.Load(); } public override void LoadInterstitial() { if (adSetting.LevelPlayInterVariable == null) return; if (!adSetting.LevelPlayInterVariable.IsReady()) adSetting.LevelPlayInterVariable.Load(); } public override void LoadRewarded() { if (adSetting.LevelPlayRewardVariable == null) return; if (!adSetting.LevelPlayRewardVariable.IsReady()) adSetting.LevelPlayRewardVariable.Load(); } public override void LoadRewardedInterstitial() { } public override void LoadAppOpen() { } public override void ShowAppOpen() { } public override void LoadNativeOverlay() { } } } ================================================ FILE: VirtueSky/Advertising/Runtime/LevelPlay/LevelPlayAdClient.cs.meta ================================================ fileFormatVersion: 2 guid: 163589e8de4d4fcaaac2df3fbf96f414 timeCreated: 1719850536 ================================================ FILE: VirtueSky/Advertising/Runtime/LevelPlay/LevelPlayAdUnitVariable.cs ================================================ using System; using UnityEngine; namespace VirtueSky.Ads { public class LevelPlayAdUnitVariable : AdUnitVariable { [SerializeField] protected string androidId; [SerializeField] protected string iOSId; [NonSerialized] private string idRuntime = string.Empty; public override bool IsShowing { get; internal set; } public override string Id { get { if (idRuntime == String.Empty) { #if UNITY_ANDROID return androidId; #elif UNITY_IOS return iOSId; #else return string.Empty; #endif } return idRuntime; } } public override AdUnitVariable Show(string placement = null) { ResetChainCallback(); if (!Application.isMobilePlatform || AdStatic.IsRemoveAd || !IsReady()) return this; ShowImpl(placement); return this; } public void SetIdRuntime(string unitId) { idRuntime = unitId; } } } ================================================ FILE: VirtueSky/Advertising/Runtime/LevelPlay/LevelPlayAdUnitVariable.cs.meta ================================================ fileFormatVersion: 2 guid: 591b3c010489423bba0d8576ef5fbe49 timeCreated: 1728631885 ================================================ FILE: VirtueSky/Advertising/Runtime/LevelPlay/LevelPlayUnitVariable/LevelPlayBannerVariable.cs ================================================ using System; #if VIRTUESKY_ADS && VIRTUESKY_LEVELPLAY using Unity.Services.LevelPlay; using VirtueSky.Core; #endif using System.Collections; using UnityEngine; using VirtueSky.Inspector; using VirtueSky.Misc; namespace VirtueSky.Ads { [Serializable] [EditorIcon("icon_scriptable")] public class LevelPlayBannerVariable : LevelPlayAdUnitVariable { public AdsSize size; public AdsPosition position; public bool isShowOnLoad; private bool _isBannerDestroyed = true; private bool _isBannerShowing; private bool _previousBannerShowStatus; #if VIRTUESKY_ADS && VIRTUESKY_LEVELPLAY private LevelPlayBannerAd bannerAd; private readonly WaitForSeconds _waitBannerReload = new WaitForSeconds(5f); private IEnumerator _reload; #endif public override void Init() { #if VIRTUESKY_ADS && VIRTUESKY_LEVELPLAY if (AdStatic.IsRemoveAd) return; _isBannerDestroyed = true; #endif } public override void Load() { #if VIRTUESKY_ADS && VIRTUESKY_LEVELPLAY if (AdStatic.IsRemoveAd) return; Destroy(); LevelPlayBannerAd.Config.Builder builder = new LevelPlayBannerAd.Config.Builder(); builder.SetPosition(ConvertBannerPosition()); builder.SetSize(ConvertBannerSize()); builder.SetDisplayOnLoad(isShowOnLoad); var config = builder.Build(); bannerAd = new LevelPlayBannerAd(Id, config); bannerAd.OnAdLoaded += BannerOnAdLoadedEvent; bannerAd.OnAdLoadFailed += BannerOnAdLoadFailedEvent; bannerAd.OnAdClicked += BannerOnAdClickedEvent; bannerAd.OnAdDisplayed += BannerOnAdDisplayedEvent; bannerAd.OnAdDisplayFailed += BannerOnAdDisplayFailedEvent; bannerAd.OnAdLeftApplication += BannerOnAdLeftApplicationEvent; bannerAd.LoadAd(); _isBannerDestroyed = false; #endif } void OnWaitAppOpenClosed() { if (_previousBannerShowStatus) { _previousBannerShowStatus = false; Show(); } } void OnWaitAppOpenDisplayed() { _previousBannerShowStatus = _isBannerShowing; if (_isBannerShowing) HideBanner(); } public override bool IsReady() { #if VIRTUESKY_ADS && VIRTUESKY_LEVELPLAY return bannerAd != null; #else return false; #endif } protected override void ShowImpl(string placement = null) { #if VIRTUESKY_ADS && VIRTUESKY_LEVELPLAY _isBannerShowing = true; IsShowing = true; AdStatic.waitAppOpenClosedAction = OnWaitAppOpenClosed; AdStatic.waitAppOpenDisplayedAction = OnWaitAppOpenDisplayed; Load(); bannerAd.ShowAd(); #endif } public override void Destroy() { #if VIRTUESKY_ADS && VIRTUESKY_LEVELPLAY _isBannerShowing = false; _isBannerDestroyed = true; IsShowing = false; AdStatic.waitAppOpenClosedAction = null; AdStatic.waitAppOpenDisplayedAction = null; bannerAd.DestroyAd(); #endif } public override void HideBanner() { base.HideBanner(); #if VIRTUESKY_ADS && VIRTUESKY_LEVELPLAY _isBannerShowing = false; IsShowing = false; bannerAd.HideAd(); #endif } #if VIRTUESKY_ADS && VIRTUESKY_LEVELPLAY private LevelPlayAdSize ConvertBannerSize() { switch (size) { case AdsSize.Banner: return LevelPlayAdSize.BANNER; case AdsSize.Adaptive: return LevelPlayAdSize.LARGE; case AdsSize.MediumRectangle: return LevelPlayAdSize.MEDIUM_RECTANGLE; case AdsSize.Leaderboard: return LevelPlayAdSize.LEADERBOARD; default: return LevelPlayAdSize.BANNER; } } private LevelPlayBannerPosition ConvertBannerPosition() { switch (position) { case AdsPosition.Bottom: return LevelPlayBannerPosition.BottomCenter; case AdsPosition.Top: return LevelPlayBannerPosition.TopCenter; default: return LevelPlayBannerPosition.BottomCenter; } } #region Fun Callback void BannerOnAdLoadedEvent(LevelPlayAdInfo adInfo) { Common.CallActionAndClean(ref loadedCallback); OnLoadAdEvent?.Invoke(); } void BannerOnAdLoadFailedEvent(LevelPlayAdError ironSourceError) { Common.CallActionAndClean(ref failedToLoadCallback); OnFailedToLoadAdEvent?.Invoke(ironSourceError.ErrorMessage); if (_reload != null) App.StopCoroutine(_reload); _reload = DelayBannerReload(); App.StartCoroutine(_reload); } private IEnumerator DelayBannerReload() { yield return _waitBannerReload; Load(); } void BannerOnAdClickedEvent(LevelPlayAdInfo adInfo) { Common.CallActionAndClean(ref clickedCallback); OnClickedAdEvent?.Invoke(); } void BannerOnAdDisplayedEvent(LevelPlayAdInfo adInfo) { IsShowing = true; Common.CallActionAndClean(ref displayedCallback); OnDisplayedAdEvent?.Invoke(); } void BannerOnAdDisplayFailedEvent(LevelPlayAdInfo adInfo, LevelPlayAdError adError) { Common.CallActionAndClean(ref failedToDisplayCallback); OnFailedToDisplayAdEvent?.Invoke(adError.ErrorMessage); } void BannerOnAdLeftApplicationEvent(LevelPlayAdInfo adInfo) { } #endregion #endif } } ================================================ FILE: VirtueSky/Advertising/Runtime/LevelPlay/LevelPlayUnitVariable/LevelPlayBannerVariable.cs.meta ================================================ fileFormatVersion: 2 guid: f5151f19197e497aa56422344920b819 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: ed5ec0bb4ec55df47af0ecc2bd7be5f9, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Advertising/Runtime/LevelPlay/LevelPlayUnitVariable/LevelPlayInterVariable.cs ================================================ using System; #if VIRTUESKY_ADS && VIRTUESKY_LEVELPLAY using Unity.Services.LevelPlay; #endif using UnityEngine; using VirtueSky.Inspector; using VirtueSky.Misc; namespace VirtueSky.Ads { [Serializable] [EditorIcon("icon_scriptable")] public class LevelPlayInterVariable : LevelPlayAdUnitVariable { [NonSerialized] internal Action completedCallback; #if VIRTUESKY_ADS && VIRTUESKY_LEVELPLAY private LevelPlayInterstitialAd interstitialAd; #endif public override void Init() { #if VIRTUESKY_ADS && VIRTUESKY_LEVELPLAY if (AdStatic.IsRemoveAd) return; #endif } public override void Load() { #if VIRTUESKY_ADS && VIRTUESKY_LEVELPLAY if (AdStatic.IsRemoveAd) return; var configBuilder = new LevelPlayInterstitialAd.Config.Builder(); var config = configBuilder.Build(); interstitialAd = new LevelPlayInterstitialAd(Id, config); interstitialAd.OnAdLoaded += InterstitialOnAdLoadedEvent; interstitialAd.OnAdLoadFailed += InterstitialOnAdLoadFailed; interstitialAd.OnAdDisplayed += InterstitialOnAdDisplayEvent; interstitialAd.OnAdClicked += InterstitialOnAdClickedEvent; interstitialAd.OnAdDisplayFailed += InterstitialOnAdDisplayFailedEvent; interstitialAd.OnAdClosed += InterstitialOnAdClosedEvent; interstitialAd.LoadAd(); #endif } public override bool IsReady() { #if VIRTUESKY_ADS && VIRTUESKY_LEVELPLAY return interstitialAd.IsAdReady(); #else return false; #endif } protected override void ShowImpl(string placement = null) { #if VIRTUESKY_ADS && VIRTUESKY_LEVELPLAY interstitialAd.ShowAd(placement); #endif } public override void Destroy() { } protected override void ResetChainCallback() { base.ResetChainCallback(); completedCallback = null; } #if VIRTUESKY_ADS && VIRTUESKY_LEVELPLAY #region Fun Callback void InterstitialOnAdLoadedEvent(LevelPlayAdInfo adInfo) { Common.CallActionAndClean(ref loadedCallback); OnLoadAdEvent?.Invoke(); } void InterstitialOnAdLoadFailed(LevelPlayAdError ironSourceError) { Common.CallActionAndClean(ref failedToLoadCallback); OnFailedToLoadAdEvent?.Invoke(ironSourceError.ErrorMessage); } void InterstitialOnAdDisplayEvent(LevelPlayAdInfo adInfo) { AdStatic.IsShowingAd = true; IsShowing = true; Common.CallActionAndClean(ref displayedCallback); OnDisplayedAdEvent?.Invoke(); } void InterstitialOnAdClickedEvent(LevelPlayAdInfo adInfo) { Common.CallActionAndClean(ref clickedCallback); OnClickedAdEvent?.Invoke(); } void InterstitialOnAdDisplayFailedEvent(LevelPlayAdInfo adInfo, LevelPlayAdError adError) { Common.CallActionAndClean(ref failedToDisplayCallback); OnFailedToDisplayAdEvent?.Invoke(adError.ErrorMessage); } void InterstitialOnAdClosedEvent(LevelPlayAdInfo adInfo) { AdStatic.IsShowingAd = false; IsShowing = false; Common.CallActionAndClean(ref completedCallback); OnClosedAdEvent?.Invoke(); Load(); } #endregion #endif } } ================================================ FILE: VirtueSky/Advertising/Runtime/LevelPlay/LevelPlayUnitVariable/LevelPlayInterVariable.cs.meta ================================================ fileFormatVersion: 2 guid: d1c4f30e37f14d78abad68a6b2d0a847 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: ed5ec0bb4ec55df47af0ecc2bd7be5f9, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Advertising/Runtime/LevelPlay/LevelPlayUnitVariable/LevelPlayRewardVariable.cs ================================================ using System; #if VIRTUESKY_ADS && VIRTUESKY_LEVELPLAY using Unity.Services.LevelPlay; #endif using VirtueSky.Inspector; using VirtueSky.Misc; namespace VirtueSky.Ads { [Serializable] [EditorIcon("icon_scriptable")] public class LevelPlayRewardVariable : LevelPlayAdUnitVariable { [NonSerialized] internal Action completedCallback; [NonSerialized] internal Action skippedCallback; public bool IsEarnRewarded { get; private set; } #if VIRTUESKY_ADS && VIRTUESKY_LEVELPLAY LevelPlayRewardedAd rewardedAd; #endif public override void Init() { #if VIRTUESKY_ADS && VIRTUESKY_LEVELPLAY if (AdStatic.IsRemoveAd) return; #endif } public override void Load() { #if VIRTUESKY_ADS && VIRTUESKY_LEVELPLAY if (AdStatic.IsRemoveAd) return; var configBuilder = new LevelPlayRewardedAd.Config.Builder(); var config = configBuilder.Build(); rewardedAd = new LevelPlayRewardedAd(Id, config); rewardedAd.OnAdLoaded += OnAdLoaded; rewardedAd.OnAdDisplayed += RewardedVideoOnAdDisplayedEvent; rewardedAd.OnAdClosed += RewardedVideoOnAdClosedEvent; rewardedAd.OnAdDisplayFailed += RewardedVideoOnAdDisplayFailedEvent; rewardedAd.OnAdRewarded += RewardedVideoOnAdRewardedEvent; rewardedAd.OnAdClicked += RewardedVideoOnAdClickedEvent; rewardedAd.OnAdLoadFailed += RewardedVideoOnAdLoadFailedEvent; rewardedAd.LoadAd(); #endif } public override bool IsReady() { #if VIRTUESKY_ADS && VIRTUESKY_LEVELPLAY return rewardedAd != null && rewardedAd.IsAdReady(); #else return false; #endif } protected override void ShowImpl(string placement = null) { #if VIRTUESKY_ADS && VIRTUESKY_LEVELPLAY rewardedAd.ShowAd(placement); #endif } public override AdUnitVariable Show(string placement = null) { ResetChainCallback(); if (!UnityEngine.Application.isMobilePlatform || !IsReady()) return this; ShowImpl(placement); return this; } public override void Destroy() { } protected override void ResetChainCallback() { base.ResetChainCallback(); completedCallback = null; skippedCallback = null; } #if VIRTUESKY_ADS && VIRTUESKY_LEVELPLAY #region Fun Callback void OnAdLoaded(LevelPlayAdInfo adInfo) { Common.CallActionAndClean(ref loadedCallback); OnLoadAdEvent?.Invoke(); } private void RewardedVideoOnAdLoadFailedEvent(LevelPlayAdError ironSourceError) { Common.CallActionAndClean(ref failedToLoadCallback); OnFailedToLoadAdEvent?.Invoke(ironSourceError.ToString()); } void RewardedVideoOnAdDisplayedEvent(LevelPlayAdInfo adInfo) { AdStatic.IsShowingAd = true; IsShowing = true; Common.CallActionAndClean(ref displayedCallback); OnDisplayedAdEvent?.Invoke(); } void RewardedVideoOnAdClosedEvent(LevelPlayAdInfo adInfo) { AdStatic.IsShowingAd = false; IsShowing = false; Common.CallActionAndClean(ref closedCallback); OnClosedAdEvent?.Invoke(); if (!IsReady()) rewardedAd.LoadAd(); if (IsEarnRewarded) { Common.CallActionAndClean(ref completedCallback); IsEarnRewarded = false; return; } Common.CallActionAndClean(ref skippedCallback); } void RewardedVideoOnAdDisplayFailedEvent(LevelPlayAdInfo adInfo, LevelPlayAdError ironSourceError) { Common.CallActionAndClean(ref failedToDisplayCallback); OnFailedToDisplayAdEvent?.Invoke(ironSourceError.ToString()); } void RewardedVideoOnAdRewardedEvent(LevelPlayAdInfo info, LevelPlayReward reward) { IsEarnRewarded = true; } void RewardedVideoOnAdClickedEvent(LevelPlayAdInfo adInfo) { Common.CallActionAndClean(ref clickedCallback); OnClickedAdEvent?.Invoke(); } #endregion #endif } } ================================================ FILE: VirtueSky/Advertising/Runtime/LevelPlay/LevelPlayUnitVariable/LevelPlayRewardVariable.cs.meta ================================================ fileFormatVersion: 2 guid: 6cb21eb6778e4c0ea10445060b08a271 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: ed5ec0bb4ec55df47af0ecc2bd7be5f9, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Advertising/Runtime/LevelPlay/LevelPlayUnitVariable.meta ================================================ fileFormatVersion: 2 guid: 7d50cc93b33f4995a04161afc0514175 timeCreated: 1719850500 ================================================ FILE: VirtueSky/Advertising/Runtime/LevelPlay.meta ================================================ fileFormatVersion: 2 guid: 1170ec045aef4f39ba9d642d37973423 timeCreated: 1719850368 ================================================ FILE: VirtueSky/Advertising/Runtime/Max/MaxAdClient.cs ================================================ using VirtueSky.Core; namespace VirtueSky.Ads { public sealed class MaxAdClient : AdClient { public MaxAdClient(AdSetting _adSetting) { adSetting = _adSetting; } public override void Initialize() { #if VIRTUESKY_ADS && VIRTUESKY_APPLOVIN MaxSdk.SetSdkKey(adSetting.SdkKey); MaxSdk.InitializeSdk(); adSetting.MaxBannerVariable.Init(); adSetting.MaxInterVariable.Init(); adSetting.MaxRewardVariable.Init(); adSetting.MaxAppOpenVariable.Init(); App.AddPauseCallback(OnAppStateChange); LoadInterstitial(); LoadRewarded(); LoadRewardedInterstitial(); LoadAppOpen(); LoadBanner(); #endif } #if VIRTUESKY_ADS && VIRTUESKY_APPLOVIN private void OnAppStateChange(bool pauseStatus) { if (!pauseStatus && adSetting.MaxAppOpenVariable.autoShow) { if (adSetting.UseAppLovin) ShowAppOpen(); } } #endif public override void LoadBanner() { if (adSetting.MaxBannerVariable == null) return; adSetting.MaxBannerVariable.Load(); } public override void LoadInterstitial() { if (adSetting.MaxInterVariable == null) return; if (!adSetting.MaxInterVariable.IsReady()) adSetting.MaxInterVariable.Load(); } public override void LoadRewarded() { if (adSetting.MaxRewardVariable == null) return; if (!adSetting.MaxRewardVariable.IsReady()) adSetting.MaxRewardVariable.Load(); } public override void LoadRewardedInterstitial() { } public override void LoadAppOpen() { if (adSetting.MaxAppOpenVariable == null) return; if (!adSetting.MaxAppOpenVariable.IsReady()) adSetting.MaxAppOpenVariable.Load(); } public override void ShowAppOpen() { if (statusAppOpenFirstIgnore) adSetting.MaxAppOpenVariable.Show(); statusAppOpenFirstIgnore = true; } public override void LoadNativeOverlay() { } } } ================================================ FILE: VirtueSky/Advertising/Runtime/Max/MaxAdClient.cs.meta ================================================ fileFormatVersion: 2 guid: ccaea541beb11497691c82e48d3e2bf7 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: ed5ec0bb4ec55df47af0ecc2bd7be5f9, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Advertising/Runtime/Max/MaxAdUnitVariable.cs ================================================ using System; using UnityEngine; namespace VirtueSky.Ads { public class MaxAdUnitVariable : AdUnitVariable { [SerializeField] protected string androidId; [SerializeField] protected string iOSId; [NonSerialized] private string idRuntime = string.Empty; public override bool IsShowing { get; internal set; } public override string Id { get { if (idRuntime == String.Empty) { #if UNITY_ANDROID return androidId; #elif UNITY_IOS return iOSId; #else return string.Empty; #endif } return idRuntime; } } public override AdUnitVariable Show(string placement = null) { ResetChainCallback(); if (!Application.isMobilePlatform || string.IsNullOrEmpty(Id) || AdStatic.IsRemoveAd || !IsReady()) return this; ShowImpl(placement); return this; } public void SetIdRuntime(string unitId) { idRuntime = unitId; } } } ================================================ FILE: VirtueSky/Advertising/Runtime/Max/MaxAdUnitVariable.cs.meta ================================================ fileFormatVersion: 2 guid: 8d49a7d460324b64bf0e810452eb8db6 timeCreated: 1728632190 ================================================ FILE: VirtueSky/Advertising/Runtime/Max/MaxUnitVariable/MaxAppOpenVariable.cs ================================================ using System; using UnityEngine; using VirtueSky.Inspector; using VirtueSky.Misc; using VirtueSky.Tracking; namespace VirtueSky.Ads { [Serializable] [EditorIcon("icon_scriptable")] public class MaxAppOpenVariable : MaxAdUnitVariable { [Tooltip("Automatically show AppOpenAd when app status is changed")] public bool autoShow = false; [Tooltip("Time between closing the previous full-screen ad and starting to show the app open ad - in seconds")] public float timeBetweenFullScreenAd = 2f; public override void Init() { #if VIRTUESKY_ADS && VIRTUESKY_APPLOVIN if (AdStatic.IsRemoveAd || string.IsNullOrEmpty(Id)) return; paidedCallback += AppTracking.TrackRevenue; MaxSdkCallbacks.AppOpen.OnAdDisplayedEvent += OnAdDisplayed; MaxSdkCallbacks.AppOpen.OnAdHiddenEvent += OnAdHidden; MaxSdkCallbacks.AppOpen.OnAdLoadedEvent += OnAdLoaded; MaxSdkCallbacks.AppOpen.OnAdDisplayFailedEvent += OnAdDisplayFailed; MaxSdkCallbacks.AppOpen.OnAdLoadFailedEvent += OnAdLoadFailed; MaxSdkCallbacks.AppOpen.OnAdRevenuePaidEvent += OnAdRevenuePaid; MaxSdkCallbacks.AppOpen.OnAdClickedEvent += OnAdClicked; #endif } public override void Load() { #if VIRTUESKY_ADS && VIRTUESKY_APPLOVIN if (AdStatic.IsRemoveAd || string.IsNullOrEmpty(Id)) return; MaxSdk.LoadAppOpenAd(Id); #endif } public override bool IsReady() { #if VIRTUESKY_ADS && VIRTUESKY_APPLOVIN return !string.IsNullOrEmpty(Id) && MaxSdk.IsAppOpenAdReady(Id) && (DateTime.Now - AdStatic.AdClosingTime).TotalSeconds > timeBetweenFullScreenAd; #else return false; #endif } protected override void ShowImpl(string placement = null) { #if VIRTUESKY_ADS && VIRTUESKY_APPLOVIN MaxSdk.ShowAppOpenAd(Id, placement: placement); #endif } public override void Destroy() { } #region Func Callback #if VIRTUESKY_ADS && VIRTUESKY_APPLOVIN private void OnAdLoaded(string unit, MaxSdkBase.AdInfo info) { Common.CallActionAndClean(ref loadedCallback); OnLoadAdEvent?.Invoke(); } private void OnAdRevenuePaid(string unit, MaxSdkBase.AdInfo info) { paidedCallback?.Invoke(info.Revenue, info.NetworkName, unit, info.AdFormat, AdMediation.AppLovin.ToString()); } private void OnAdLoadFailed(string unit, MaxSdkBase.ErrorInfo info) { Common.CallActionAndClean(ref failedToLoadCallback); OnFailedToLoadAdEvent?.Invoke(info.Message); } private void OnAdDisplayFailed(string unit, MaxSdkBase.ErrorInfo errorInfo, MaxSdkBase.AdInfo info) { Common.CallActionAndClean(ref failedToDisplayCallback); OnFailedToDisplayAdEvent?.Invoke(errorInfo.Message); } private void OnAdHidden(string unit, MaxSdkBase.AdInfo info) { AdStatic.waitAppOpenClosedAction?.Invoke(); AdStatic.IsShowingAd = false; IsShowing = false; Common.CallActionAndClean(ref closedCallback); OnClosedAdEvent?.Invoke(); if (!string.IsNullOrEmpty(Id)) MaxSdk.LoadAppOpenAd(Id); } private void OnAdDisplayed(string unit, MaxSdkBase.AdInfo info) { AdStatic.waitAppOpenDisplayedAction?.Invoke(); AdStatic.IsShowingAd = true; IsShowing = true; Common.CallActionAndClean(ref displayedCallback); OnDisplayedAdEvent?.Invoke(); } private void OnAdClicked(string unit, MaxSdkBase.AdInfo info) { Common.CallActionAndClean(ref clickedCallback); OnClickedAdEvent?.Invoke(); } #endif #endregion } } ================================================ FILE: VirtueSky/Advertising/Runtime/Max/MaxUnitVariable/MaxAppOpenVariable.cs.meta ================================================ fileFormatVersion: 2 guid: 1e29fec6165f4c3baceac878abc88638 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: ed5ec0bb4ec55df47af0ecc2bd7be5f9, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Advertising/Runtime/Max/MaxUnitVariable/MaxBannerVariable.cs ================================================ using System; using UnityEngine; using VirtueSky.Inspector; using VirtueSky.Misc; using VirtueSky.Tracking; namespace VirtueSky.Ads { [Serializable] [EditorIcon("icon_scriptable")] public class MaxBannerVariable : MaxAdUnitVariable { public AdsSize size; public AdsPosition position; private bool _isBannerDestroyed = true; private bool _isBannerShowing; private bool _previousBannerShowStatus; public override void Init() { #if VIRTUESKY_ADS && VIRTUESKY_APPLOVIN if (AdStatic.IsRemoveAd || string.IsNullOrEmpty(Id)) return; paidedCallback += AppTracking.TrackRevenue; MaxSdkCallbacks.Banner.OnAdLoadedEvent += OnAdLoaded; MaxSdkCallbacks.Banner.OnAdExpandedEvent += OnAdExpanded; MaxSdkCallbacks.Banner.OnAdLoadFailedEvent += OnAdLoadFailed; MaxSdkCallbacks.Banner.OnAdCollapsedEvent += OnAdCollapsed; MaxSdkCallbacks.Banner.OnAdRevenuePaidEvent += OnAdRevenuePaid; MaxSdkCallbacks.Banner.OnAdClickedEvent += OnAdClicked; if (size != AdsSize.Adaptive) { MaxSdk.SetBannerExtraParameter(Id, "adaptive_banner", "false"); } #endif } public override void Load() { #if VIRTUESKY_ADS && VIRTUESKY_APPLOVIN if (AdStatic.IsRemoveAd || string.IsNullOrEmpty(Id)) return; if (_isBannerDestroyed) { MaxSdk.CreateBanner(Id, ConvertPosition()); _isBannerDestroyed = false; } #endif } void OnWaitAppOpenClosed() { if (_previousBannerShowStatus) { _previousBannerShowStatus = false; Show(); } } void OnWaitAppOpenDisplayed() { _previousBannerShowStatus = _isBannerShowing; if (_isBannerShowing) HideBanner(); } public override bool IsReady() { #if VIRTUESKY_ADS && VIRTUESKY_APPLOVIN return !string.IsNullOrEmpty(Id); #else return false; #endif } protected override void ShowImpl(string placement = null) { #if VIRTUESKY_ADS && VIRTUESKY_APPLOVIN _isBannerShowing = true; IsShowing = true; AdStatic.waitAppOpenClosedAction = OnWaitAppOpenClosed; AdStatic.waitAppOpenDisplayedAction = OnWaitAppOpenDisplayed; Load(); MaxSdk.ShowBanner(Id); #endif } public override void Destroy() { #if VIRTUESKY_ADS && VIRTUESKY_APPLOVIN if (string.IsNullOrEmpty(Id)) return; _isBannerShowing = false; _isBannerDestroyed = true; IsShowing = false; AdStatic.waitAppOpenClosedAction = null; AdStatic.waitAppOpenDisplayedAction = null; MaxSdk.DestroyBanner(Id); #endif } public override void HideBanner() { base.HideBanner(); #if VIRTUESKY_ADS && VIRTUESKY_APPLOVIN _isBannerShowing = false; IsShowing = false; if (string.IsNullOrEmpty(Id)) return; MaxSdk.HideBanner(Id); #endif } #region Fun Callback #if VIRTUESKY_ADS && VIRTUESKY_APPLOVIN public MaxSdkBase.BannerPosition ConvertPosition() { switch (position) { case AdsPosition.Top: return MaxSdkBase.BannerPosition.TopCenter; case AdsPosition.Bottom: return MaxSdkBase.BannerPosition.BottomCenter; case AdsPosition.TopLeft: return MaxSdkBase.BannerPosition.TopLeft; case AdsPosition.TopRight: return MaxSdkBase.BannerPosition.TopRight; case AdsPosition.BottomLeft: return MaxSdkBase.BannerPosition.BottomLeft; case AdsPosition.BottomRight: return MaxSdkBase.BannerPosition.BottomRight; default: return MaxSdkBase.BannerPosition.BottomCenter; } } private void OnAdRevenuePaid(string unit, MaxSdkBase.AdInfo info) { paidedCallback?.Invoke(info.Revenue, info.NetworkName, unit, info.AdFormat, AdMediation.AppLovin.ToString()); } private void OnAdLoaded(string unit, MaxSdkBase.AdInfo info) { Common.CallActionAndClean(ref loadedCallback); OnLoadAdEvent?.Invoke(); } private void OnAdExpanded(string unit, MaxSdkBase.AdInfo info) { Common.CallActionAndClean(ref displayedCallback); OnDisplayedAdEvent?.Invoke(); } private void OnAdLoadFailed(string unit, MaxSdkBase.ErrorInfo info) { Common.CallActionAndClean(ref failedToLoadCallback); OnFailedToLoadAdEvent?.Invoke(info.Message); Destroy(); } private void OnAdCollapsed(string unit, MaxSdkBase.AdInfo info) { Common.CallActionAndClean(ref closedCallback); OnClosedAdEvent?.Invoke(); } private void OnAdClicked(string arg1, MaxSdkBase.AdInfo arg2) { Common.CallActionAndClean(ref clickedCallback); OnClickedAdEvent?.Invoke(); } #endif #endregion } } ================================================ FILE: VirtueSky/Advertising/Runtime/Max/MaxUnitVariable/MaxBannerVariable.cs.meta ================================================ fileFormatVersion: 2 guid: 2d54005e18d14434a4feed9988bfd43c MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: ed5ec0bb4ec55df47af0ecc2bd7be5f9, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Advertising/Runtime/Max/MaxUnitVariable/MaxInterVariable.cs ================================================ using System; using UnityEngine; using VirtueSky.Ads; using VirtueSky.Inspector; using VirtueSky.Misc; using VirtueSky.Tracking; namespace VirtueSky.Ads { [Serializable] [EditorIcon("icon_scriptable")] public class MaxInterVariable : MaxAdUnitVariable { [NonSerialized] internal Action completedCallback; public override void Init() { #if VIRTUESKY_ADS && VIRTUESKY_APPLOVIN if (AdStatic.IsRemoveAd || string.IsNullOrEmpty(Id)) return; paidedCallback += AppTracking.TrackRevenue; MaxSdkCallbacks.Interstitial.OnAdLoadedEvent += OnAdLoaded; MaxSdkCallbacks.Interstitial.OnAdLoadFailedEvent += OnAdLoadFailed; MaxSdkCallbacks.Interstitial.OnAdRevenuePaidEvent += OnAdRevenuePaid; MaxSdkCallbacks.Interstitial.OnAdDisplayedEvent += OnAdDisplayed; MaxSdkCallbacks.Interstitial.OnAdHiddenEvent += OnAdHidden; MaxSdkCallbacks.Interstitial.OnAdDisplayFailedEvent += OnAdDisplayFailed; MaxSdkCallbacks.Interstitial.OnAdClickedEvent += OnAdClicked; #endif } public override void Load() { #if VIRTUESKY_ADS && VIRTUESKY_APPLOVIN if (AdStatic.IsRemoveAd || string.IsNullOrEmpty(Id)) return; MaxSdk.LoadInterstitial(Id); #endif } public override bool IsReady() { #if VIRTUESKY_ADS && VIRTUESKY_APPLOVIN return !string.IsNullOrEmpty(Id) && MaxSdk.IsInterstitialReady(Id); #else return false; #endif } protected override void ShowImpl(string placement = null) { #if VIRTUESKY_ADS && VIRTUESKY_APPLOVIN MaxSdk.ShowInterstitial(Id, placement: placement); #endif } public override void Destroy() { } protected override void ResetChainCallback() { base.ResetChainCallback(); completedCallback = null; } #region Func Callback #if VIRTUESKY_ADS && VIRTUESKY_APPLOVIN private void OnAdDisplayFailed(string unit, MaxSdkBase.ErrorInfo error, MaxSdkBase.AdInfo info) { Common.CallActionAndClean(ref failedToDisplayCallback); OnFailedToDisplayAdEvent?.Invoke(error.Message); } private void OnAdHidden(string unit, MaxSdkBase.AdInfo info) { AdStatic.IsShowingAd = false; IsShowing = false; Common.CallActionAndClean(ref completedCallback); OnClosedAdEvent?.Invoke(); if (!string.IsNullOrEmpty(Id)) MaxSdk.LoadInterstitial(Id); } private void OnAdDisplayed(string unit, MaxSdkBase.AdInfo info) { AdStatic.IsShowingAd = true; IsShowing = true; Common.CallActionAndClean(ref displayedCallback); OnDisplayedAdEvent?.Invoke(); } private void OnAdRevenuePaid(string unit, MaxSdkBase.AdInfo info) { paidedCallback?.Invoke(info.Revenue, info.NetworkName, unit, info.AdFormat, AdMediation.AppLovin.ToString()); } private void OnAdLoadFailed(string unit, MaxSdkBase.ErrorInfo info) { Common.CallActionAndClean(ref failedToLoadCallback); OnFailedToLoadAdEvent?.Invoke(info.Message); } private void OnAdLoaded(string unit, MaxSdkBase.AdInfo info) { Common.CallActionAndClean(ref loadedCallback); OnLoadAdEvent?.Invoke(); } private void OnAdClicked(string unit, MaxSdkBase.AdInfo info) { Common.CallActionAndClean(ref clickedCallback); OnClickedAdEvent?.Invoke(); } #endif #endregion } } ================================================ FILE: VirtueSky/Advertising/Runtime/Max/MaxUnitVariable/MaxInterVariable.cs.meta ================================================ fileFormatVersion: 2 guid: 7f2517077a9341d38d7486727d83a132 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: ed5ec0bb4ec55df47af0ecc2bd7be5f9, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Advertising/Runtime/Max/MaxUnitVariable/MaxRewardVariable.cs ================================================ using System; using UnityEngine; using VirtueSky.Inspector; using VirtueSky.Misc; using VirtueSky.Tracking; namespace VirtueSky.Ads { [Serializable] [EditorIcon("icon_scriptable")] public class MaxRewardVariable : MaxAdUnitVariable { [NonSerialized] internal Action completedCallback; [NonSerialized] internal Action skippedCallback; public bool IsEarnRewarded { get; private set; } public override void Init() { #if VIRTUESKY_ADS && VIRTUESKY_APPLOVIN if (string.IsNullOrEmpty(Id)) return; paidedCallback += AppTracking.TrackRevenue; MaxSdkCallbacks.Rewarded.OnAdDisplayedEvent += OnAdDisplayed; MaxSdkCallbacks.Rewarded.OnAdHiddenEvent += OnAdHidden; MaxSdkCallbacks.Rewarded.OnAdLoadedEvent += OnAdLoaded; MaxSdkCallbacks.Rewarded.OnAdDisplayFailedEvent += OnAdDisplayFailed; MaxSdkCallbacks.Rewarded.OnAdLoadFailedEvent += OnAdLoadFailed; MaxSdkCallbacks.Rewarded.OnAdRevenuePaidEvent += OnAdRevenuePaid; MaxSdkCallbacks.Rewarded.OnAdReceivedRewardEvent += OnAdReceivedReward; MaxSdkCallbacks.Rewarded.OnAdClickedEvent += OnAdClicked; #endif } public override void Load() { #if VIRTUESKY_ADS && VIRTUESKY_APPLOVIN if (string.IsNullOrEmpty(Id)) return; MaxSdk.LoadRewardedAd(Id); #endif } public override bool IsReady() { #if VIRTUESKY_ADS && VIRTUESKY_APPLOVIN return !string.IsNullOrEmpty(Id) && MaxSdk.IsRewardedAdReady(Id); #else return false; #endif } protected override void ShowImpl(string placement = null) { #if VIRTUESKY_ADS && VIRTUESKY_APPLOVIN MaxSdk.ShowRewardedAd(Id, placement: placement); #endif } public override AdUnitVariable Show(string placement = null) { ResetChainCallback(); if (!UnityEngine.Application.isMobilePlatform || !IsReady()) return this; ShowImpl(placement); return this; } public override void Destroy() { } protected override void ResetChainCallback() { base.ResetChainCallback(); completedCallback = null; skippedCallback = null; } #region Func Callback #if VIRTUESKY_ADS && VIRTUESKY_APPLOVIN private void OnAdReceivedReward(string unit, MaxSdkBase.Reward reward, MaxSdkBase.AdInfo info) { IsEarnRewarded = true; } private void OnAdRevenuePaid(string unit, MaxSdkBase.AdInfo info) { paidedCallback?.Invoke(info.Revenue, info.NetworkName, unit, info.AdFormat, AdMediation.AppLovin.ToString()); } private void OnAdLoadFailed(string unit, MaxSdkBase.ErrorInfo info) { Common.CallActionAndClean(ref failedToLoadCallback); OnFailedToLoadAdEvent?.Invoke(info.Message); } private void OnAdDisplayFailed(string unit, MaxSdkBase.ErrorInfo errorInfo, MaxSdkBase.AdInfo info) { Common.CallActionAndClean(ref failedToDisplayCallback); OnFailedToDisplayAdEvent?.Invoke(errorInfo.Message); } private void OnAdLoaded(string unit, MaxSdkBase.AdInfo info) { Common.CallActionAndClean(ref loadedCallback); OnLoadAdEvent?.Invoke(); } private void OnAdHidden(string unit, MaxSdkBase.AdInfo info) { AdStatic.IsShowingAd = false; IsShowing = false; Common.CallActionAndClean(ref closedCallback); OnClosedAdEvent?.Invoke(); if (!IsReady()) MaxSdk.LoadRewardedAd(Id); if (IsEarnRewarded) { Common.CallActionAndClean(ref completedCallback); IsEarnRewarded = false; return; } Common.CallActionAndClean(ref skippedCallback); } private void OnAdDisplayed(string unit, MaxSdkBase.AdInfo info) { AdStatic.IsShowingAd = true; IsShowing = true; Common.CallActionAndClean(ref displayedCallback); OnDisplayedAdEvent?.Invoke(); } private void OnAdClicked(string unit, MaxSdkBase.AdInfo info) { Common.CallActionAndClean(ref clickedCallback); OnClickedAdEvent?.Invoke(); } #endif #endregion } } ================================================ FILE: VirtueSky/Advertising/Runtime/Max/MaxUnitVariable/MaxRewardVariable.cs.meta ================================================ fileFormatVersion: 2 guid: 20d8d1652da34664a50db28dbc997814 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: ed5ec0bb4ec55df47af0ecc2bd7be5f9, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Advertising/Runtime/Max/MaxUnitVariable.meta ================================================ fileFormatVersion: 2 guid: 74b6a60977c643ee956805295399665c timeCreated: 1695462087 ================================================ FILE: VirtueSky/Advertising/Runtime/Max.meta ================================================ fileFormatVersion: 2 guid: f30fd55eb75a48b4691e1a17d8ad50c2 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Advertising/Runtime/Virtuesky.Sunflower.Advertising.asmdef ================================================ { "name": "Virtuesky.Sunflower.Advertising", "rootNamespace": "", "references": [ "GUID:fca7ec166e04dc948b624a983315e2c9", "GUID:acb3cac55c622ec459c8caadf707623a", "GUID:32dbaa332e571bf429b7de517f75f074", "GUID:bd40169efe8642149b1d2b72ba4903ce", "GUID:c904f6d969e991d459a0843b71c22ec5", "GUID:324caed91501a9c47a04ebfd87b68794", "GUID:a4cfc1a18fa3a469b96d885db522f42e", "GUID:35d694408290717499b3838802212c7f", "GUID:5e9107a8f2499184ea26564811dda246", "GUID:760a4c7888534400e882b82c5b3fba06", "GUID:00c479e63b1c74419820a39073267645", "GUID:c282fd4f3fc2c7540914e85842a013c7" ], "includePlatforms": [], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], "versionDefines": [], "noEngineReferences": false } ================================================ FILE: VirtueSky/Advertising/Runtime/Virtuesky.Sunflower.Advertising.asmdef.meta ================================================ fileFormatVersion: 2 guid: abd57f653a468a04c8d4e281527ff293 AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Advertising/Runtime.meta ================================================ fileFormatVersion: 2 guid: f71c7d92eeff8c34492800ba35756ee8 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Advertising.meta ================================================ fileFormatVersion: 2 guid: 4a6fce59e6956244e8e4045dcfa6387c folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/AssetFinder.cs ================================================ using System; using System.Collections.Generic; using System.IO; using System.Linq; using UnityEditor; using UnityEngine; using UnityObject = UnityEngine.Object; namespace VirtueSky.AssetFinder.Editor { public enum Dependency { All, Direct, Indirect } public enum DepthFilter { All, Equal, NotEqual, Less, LessEqual, Greater, GreaterEqual } public enum Sorting { None, Type, Path, Size } [Serializable] public class AssetFinderInfo { public string guid; public string assetPath; public string fileName; public string extension; public System.Type assetType; public int usageCount; public int usedByCount; public bool isInBuild; public long fileSize; public bool isFolder; public bool isBuiltin; public AssetFinderInfo(string guid) { this.guid = guid; RefreshInfo(); } internal void RefreshInfo() { if (string.IsNullOrEmpty(guid)) return; assetPath = AssetDatabase.GUIDToAssetPath(guid); if (string.IsNullOrEmpty(assetPath)) { fileName = "Missing"; extension = ""; assetType = null; fileSize = 0; isFolder = false; isBuiltin = false; return; } fileName = Path.GetFileName(assetPath); extension = Path.GetExtension(assetPath); // Check if it's a folder isFolder = AssetDatabase.IsValidFolder(assetPath); // Check if it's builtin using the proper constant isBuiltin = AssetFinderAsset.BUILT_IN_ASSETS.Contains(guid); if (!isFolder) { UnityObject obj = AssetDatabase.LoadAssetAtPath(assetPath); assetType = obj?.GetType(); // Get file size try { if (File.Exists(assetPath)) { var fileInfo = new FileInfo(assetPath); fileSize = fileInfo.Length; } } catch { fileSize = 0; } } else { assetType = typeof(DefaultAsset); fileSize = 0; } // Get usage counts from AssetFinderAsset if available if (AssetFinderCache.isReady) { AssetFinderAsset asset = AssetFinderCache.Api.Get(guid); if (asset != null) { usageCount = asset.UseGUIDsCount; usedByCount = asset.UsedByMap.Count; } } } internal void UpdateBuildStatus(HashSet buildGuids) { isInBuild = buildGuids != null && buildGuids.Contains(guid); } } public static class AssetFinder { public static bool IsReady => AssetFinderCache.isReady; public static void ScanProject() { AssetFinderCache.DeleteCache(); AssetFinderCache.CreateCache(); } public static void Refresh() { if (!AssetFinderCache.hasCache) { AssetFinderLOG.LogWarning("AssetFinder cache not found. Use AssetFinder.ScanProject() first."); return; } AssetFinderCache.Api.Check4Changes(true); } public static List GetUses(string[] guids, Dependency dep = Dependency.All, int depth = 0, DepthFilter filter = DepthFilter.All, Sorting sort = Sorting.None) { if (!IsReady) { AssetFinderLOG.LogWarning("AssetFinder cache not ready. Use AssetFinder.ScanProject() first."); return new List(); } if (guids == null || guids.Length == 0) return new List(); Dictionary refs = AssetFinderRef.FindUsage(guids); return ProcessResults(refs, dep, depth, filter, sort); } public static List GetUsedBy(string[] guids, Dependency dep = Dependency.All, int depth = 0, DepthFilter filter = DepthFilter.All, Sorting sort = Sorting.None) { if (!IsReady) { AssetFinderLOG.LogWarning("AssetFinder cache not ready. Use AssetFinder.ScanProject() first."); return new List(); } if (guids == null || guids.Length == 0) return new List(); Dictionary refs = AssetFinderRef.FindUsedBy(guids); return ProcessResults(refs, dep, depth, filter, sort); } public static List GetUnused(Sorting sort = Sorting.None) { if (!IsReady) { AssetFinderLOG.LogWarning("AssetFinder cache not ready. Use AssetFinder.ScanProject() first."); return new List(); } List unusedAssets = AssetFinderCache.Api.ScanUnused(true); return ProcessAssetResults(unusedAssets, sort); } public static List GetInBuild(Sorting sort = Sorting.None) { if (!IsReady) { AssetFinderLOG.LogWarning("AssetFinder cache not ready. Use AssetFinder.ScanProject() first."); return new List(); } var usedInBuild = new AssetFinderUsedInBuild(null, () => ConvertSorting(sort), () => AssetFinderRefDrawer.Mode.Type); usedInBuild.RefreshView(); if (usedInBuild.refs == null) return new List(); var buildGuids = new HashSet(usedInBuild.refs.Keys); var assets = usedInBuild.refs.Values.Select(r => r.asset).ToList(); var results = ProcessAssetResults(assets, sort); // Set isInBuild flag for all returned assets foreach (var assetInfo in results) { assetInfo.UpdateBuildStatus(buildGuids); } return results; } public static Dictionary GetUsesCount(string[] guids) { var result = new Dictionary(); if (!IsReady) { AssetFinderLOG.LogWarning("AssetFinder cache not ready. Use AssetFinder.ScanProject() first."); return result; } if (guids == null || guids.Length == 0) return result; foreach (string guid in guids) { if (string.IsNullOrEmpty(guid)) continue; AssetFinderAsset asset = AssetFinderCache.Api.Get(guid); result[guid] = asset?.UseGUIDsCount ?? 0; } return result; } public static Dictionary GetUsedByCount(string[] guids) { var result = new Dictionary(); if (!IsReady) { AssetFinderLOG.LogWarning("AssetFinder cache not ready. Use AssetFinder.ScanProject() first."); return result; } if (guids == null || guids.Length == 0) return result; foreach (string guid in guids) { if (string.IsNullOrEmpty(guid)) continue; AssetFinderAsset asset = AssetFinderCache.Api.Get(guid); result[guid] = asset?.UsedByMap.Count ?? 0; } return result; } public static bool IsUses(string[] guids) { if (!IsReady || guids == null || guids.Length == 0) return false; foreach (string guid in guids) { if (string.IsNullOrEmpty(guid)) continue; AssetFinderAsset asset = AssetFinderCache.Api.Get(guid); if (asset != null && asset.UseGUIDsCount > 0) return true; } return false; } public static bool IsUsedBy(string[] guids) { if (!IsReady || guids == null || guids.Length == 0) return false; foreach (string guid in guids) { if (string.IsNullOrEmpty(guid)) continue; AssetFinderAsset asset = AssetFinderCache.Api.Get(guid); if (asset != null && asset.UsedByMap.Count > 0) return true; } return false; } public static bool IsInBuild(string[] guids) { if (!IsReady) { AssetFinderLOG.LogWarning("AssetFinder cache not ready. Use AssetFinder.ScanProject() first."); return false; } if (guids == null || guids.Length == 0) return false; var usedInBuild = new AssetFinderUsedInBuild(null, () => AssetFinderRefDrawer.Sort.Type, () => AssetFinderRefDrawer.Mode.Type); usedInBuild.RefreshView(); if (usedInBuild.refs == null) return false; var buildGuids = new HashSet(usedInBuild.refs.Keys); foreach (string guid in guids) { if (buildGuids.Contains(guid)) return true; } return false; } private static List ProcessAssetResults(List assets, Sorting sorting) { if (assets == null) return new List(); var results = new List(); foreach (AssetFinderAsset asset in assets) { if (asset == null) continue; var assetInfo = new AssetFinderInfo(asset.guid); results.Add(assetInfo); } return ApplySorting(results, sorting); } private static List ProcessResults(Dictionary refs, Dependency dependency, int depth, DepthFilter filter, Sorting sorting) { if (refs == null) return new List(); var results = new List(); var processedGuids = new HashSet(); foreach (KeyValuePair kvp in refs) { AssetFinderRef refItem = kvp.Value; // Apply dependency filter if (dependency == Dependency.Direct && refItem.depth > 1) continue; if (dependency == Dependency.Indirect && refItem.depth <= 1) continue; // Apply depth filter with mathematically correct comparisons if (!MatchesDepthFilter(refItem.depth, depth, filter)) continue; if (processedGuids.Contains(refItem.asset.guid)) continue; processedGuids.Add(refItem.asset.guid); var assetInfo = new AssetFinderInfo(refItem.asset.guid); results.Add(assetInfo); } return ApplySorting(results, sorting); } private static bool MatchesDepthFilter(int itemDepth, int targetDepth, DepthFilter filter) { switch (filter) { case DepthFilter.All: return true; case DepthFilter.Equal: return itemDepth == targetDepth; case DepthFilter.NotEqual: return itemDepth != targetDepth; case DepthFilter.Less: return itemDepth < targetDepth; case DepthFilter.LessEqual: return itemDepth <= targetDepth; case DepthFilter.Greater: return itemDepth > targetDepth; case DepthFilter.GreaterEqual: return itemDepth >= targetDepth; default: return true; } } private static List ApplySorting(List assetInfos, Sorting sorting) { switch (sorting) { case Sorting.Type: return assetInfos.OrderBy(info => info.assetType?.Name ?? "") .ThenBy(info => info.assetPath) .ToList(); case Sorting.Path: return assetInfos.OrderBy(info => info.assetPath) .ThenBy(info => info.assetType?.Name ?? "") .ToList(); case Sorting.Size: return assetInfos.OrderByDescending(info => info.fileSize) .ThenBy(info => info.assetPath) .ToList(); default: return assetInfos; } } private static AssetFinderRefDrawer.Sort ConvertSorting(Sorting sorting) { switch (sorting) { case Sorting.Type: return AssetFinderRefDrawer.Sort.Type; case Sorting.Path: return AssetFinderRefDrawer.Sort.Path; case Sorting.Size: return AssetFinderRefDrawer.Sort.Size; default: return AssetFinderRefDrawer.Sort.Type; } } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/AssetFinder.cs.meta ================================================ fileFormatVersion: 2 guid: 336a181c1abdb455f8388370e58f0496 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/AssetFinderAssetType.cs ================================================ // deleted ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/AssetFinderAssetType.cs.meta ================================================ fileFormatVersion: 2 guid: b077597d32a3b4e43bd7bfc007c3e6dc MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/AssetFinderCacheEditor.cs ================================================ // deleted ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/AssetFinderCacheEditor.cs.meta ================================================ fileFormatVersion: 2 guid: 18708e9bf7db0f04fa917a0db924382c MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/AssetFinderDuplicate.cs ================================================ // deleted ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/AssetFinderDuplicate.cs.meta ================================================ fileFormatVersion: 2 guid: 57aae5701da3c644c937c59e2da6da85 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/AssetFinderRef.cs ================================================ // deleted ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/AssetFinderRef.cs.meta ================================================ fileFormatVersion: 2 guid: 7ef09719313b4f943a49eb3a2b0f934d MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/AssetFinderWindowExtension.cs ================================================ namespace VirtueSky.AssetFinder.Editor { public class AssetFinderWindowExtension { public static void ShowWindow() { AssetFinderWindowAll.ShowWindow(); } public static void DeleteCache() { AssetFinderCache.DeleteCache(); } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/AssetFinderWindowExtension.cs.meta ================================================ fileFormatVersion: 2 guid: 10b0c9ac533b455baa0c863c779748bd timeCreated: 1764820294 ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderAsset.AssetState.cs ================================================ namespace VirtueSky.AssetFinder.Editor { partial class AssetFinderAsset { public enum AssetState { NEW, CACHE, MISSING } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderAsset.AssetState.cs.meta ================================================ fileFormatVersion: 2 guid: cd01dcf20ca0ec442af562e1bb400560 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderAsset.AssetType.cs ================================================ namespace VirtueSky.AssetFinder.Editor { partial class AssetFinderAsset { public enum AssetType { UNKNOWN, FOLDER, SCRIPT, SCENE, DLL, REFERENCABLE, BINARY_ASSET, MODEL, TERRAIN, LIGHTING_DATA, NON_READABLE, BUILT_IN } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderAsset.AssetType.cs.meta ================================================ fileFormatVersion: 2 guid: 0d8fbadc1183faf4fa0008a3c8ef122e MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderAsset.Classes.cs ================================================ using System; using System.Collections.Generic; namespace VirtueSky.AssetFinder.Editor { internal partial class AssetFinderAsset { [Serializable] internal class Classes { public string guid; public List ids; } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderAsset.Classes.cs.meta ================================================ fileFormatVersion: 2 guid: 5474ab83390e2904b92f5b45bd2fe0dc MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderAsset.Constants.cs ================================================ using System; using System.Collections.Generic; using UnityEngine; namespace VirtueSky.AssetFinder.Editor { internal partial class AssetFinderAsset { // ------------------------------ CONSTANTS --------------------------- public const int MIN_FILE_SIZE_2LOG = 1024 * 1024; // 1 MB internal static bool shouldWriteImportLog; private static readonly HashSet SCRIPT_EXTENSIONS = new HashSet { ".cs", ".js", ".boo", ".h", ".java", ".cpp", ".m", ".mm", ".cginclude", ".shadersubgraph" }; private static readonly HashSet REFERENCABLE_EXTENSIONS = new HashSet { ".anim", ".controller", ".mat", ".unity", ".guiskin", ".prefab", ".overridecontroller", ".mask", ".rendertexture", ".cubemap", ".flare", ".playable", ".mat", ".physicsmaterial", ".fontsettings", ".asset", ".prefs", ".spriteatlas", ".terrainlayer", ".asmdef", ".preset", ".spriteLib", ".shader", ".hlsl", ".cginc", ".glsl" }; private static readonly HashSet REFERENCABLE_JSON = new HashSet { ".shadergraph", ".shadersubgraph" }; private static readonly HashSet UI_TOOLKIT = new HashSet { ".uss", ".uxml", ".tss" }; private static readonly HashSet REFERENCABLE_META = new HashSet { ".texture2darray", ".png", ".jpg", ".jpeg", ".tga", ".tif", ".tiff", ".psd", ".bmp", ".exr", ".gif", }; /// /// Extensions that rarely contain references to other assets and can be /// ignored when deciding if an asset is "critical". /// private static readonly HashSet NON_REFERENCE_EXTENSIONS = new HashSet(StringComparer.OrdinalIgnoreCase) { ".wav", ".mp3", ".ogg", ".aif", ".aiff", ".txt", ".json", ".xml", ".csv", ".html", ".htm", ".yaml", ".md" }; internal static readonly HashSet BUILT_IN_ASSETS = new HashSet { "0000000000000000f000000000000000", "0000000000000000e000000000000000", "0000000000000000d000000000000000" }; private static readonly Dictionary HashClasses = new Dictionary(); internal static Dictionary cacheImage = new Dictionary(); public static float ignoreTS; private static string _logPath; private static int binaryLoaded; private static DateTime scanStartTime; private static string logPath { get { if (!string.IsNullOrEmpty(_logPath)) return _logPath; _logPath = System.IO.Path.Combine(Application.dataPath, "../fr2-import.log"); return _logPath; } } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderAsset.Constants.cs.meta ================================================ fileFormatVersion: 2 guid: 9e3eb5ee34a8a3a41b281a3f9d1652e8 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderAsset.ContentLoader.cs ================================================ using System; using System.IO; using System.Collections.Generic; using UnityEditor; using UnityEngine; using UnityObject = UnityEngine.Object; namespace VirtueSky.AssetFinder.Editor { internal partial class AssetFinderAsset { // ----------------------------- CONTENT LOADING --------------------------------------- internal void LoadContent() { if (!fileContentDirty) return; m_cachefileWriteTS = m_fileWriteTS; m_forceIncludeInBuild = false; if (IsMissing || type == AssetType.NON_READABLE) return; if (type == AssetType.DLL) { AssetFinderLOG.LogWarning("Parsing DLL not yet supportted "); return; } AssetFinderLOG.Log("LoadContent ... infoHash=" + fileInfoHash + ": assetPath=" + m_assetPath); var startTime = DateTime.Now; if (shouldWriteImportLog && (fileSize >= MIN_FILE_SIZE_2LOG)) { var logMessage = $"{startTime:yyyy-MM-dd HH:mm:ss} - {assetPath}, Size: {fileSize} bytes"; File.AppendAllText(logPath, logMessage + Environment.NewLine); } if (!ExistOnDisk()) { state = AssetState.MISSING; return; } ClearUseGUIDs(); if (IsFolder) { LoadFolder(); } else if (IsReferencable) { LoadYAML2(); } else if (IsBinaryAsset) { LoadBinaryAsset(); } if (shouldWriteImportLog && (fileSize >= MIN_FILE_SIZE_2LOG)) { DateTime endTime = DateTime.Now; double duration = (endTime - startTime).TotalMilliseconds; var logMessage = $", Duration: {duration} ms"; File.AppendAllText(logPath, logMessage + Environment.NewLine); } } internal void LoadContentFast() { if (!fileContentDirty) return; m_cachefileWriteTS = m_fileWriteTS; m_forceIncludeInBuild = false; if (IsMissing) return; if (type == AssetType.SCRIPT || type == AssetType.DLL || type == AssetType.FOLDER) return; // if (assetPath.StartsWith("Packages/")) return; DateTime startTime = DateTime.Now; if (shouldWriteImportLog && (fileSize >= MIN_FILE_SIZE_2LOG)) { var logMessage = $"{startTime:yyyy-MM-dd HH:mm:ss} - {assetPath}, Size: {fileSize} bytes"; File.AppendAllText(logPath, logMessage); } ClearUseGUIDs(); if (fileSize > 5 * 1024 * 1024 || type == AssetType.NON_READABLE || IsBinaryAsset) { string[] dependencies = AssetDatabase.GetDependencies(assetPath, false); foreach (string dependency in dependencies) { string guid = AssetDatabase.AssetPathToGUID(dependency); if (!string.IsNullOrEmpty(guid) && (guid != this.guid)) { AddUseGUID(guid); } } } else if (IsReferencable) { LoadYAML2(); } // CRITICAL FIX: Validate with AssetDatabase to catch missing references using (AssetFinderDev.NoLog) { ValidateWithAssetDatabase(); } if (shouldWriteImportLog && (fileSize >= MIN_FILE_SIZE_2LOG)) { DateTime endTime = DateTime.Now; double duration = (endTime - startTime).TotalMilliseconds; var logMessage = $", Duration: {duration} ms"; File.AppendAllText(logPath, logMessage + Environment.NewLine); } } internal void ValidateWithAssetDatabase() { if (IsMissing || IsFolder || type == AssetType.SCRIPT) return; try { // Get Unity's known dependencies string[] unityDeps = AssetDatabase.GetDependencies(assetPath, false); if (unityDeps == null) return; var unityGuids = new HashSet(); foreach (string depPath in unityDeps) { if (depPath == assetPath) continue; // Skip self-reference string depGuid = AssetDatabase.AssetPathToGUID(depPath); if (!string.IsNullOrEmpty(depGuid)) unityGuids.Add(depGuid); } // Compare with FR2's parsed results var fr2Guids = new HashSet(UseGUIDs.Keys); var missingInFR2 = new List(); // Find guids in Unity but not in FR2 foreach (string unityGuid in unityGuids) { if (!fr2Guids.Contains(unityGuid)) missingInFR2.Add(unityGuid); } if (missingInFR2.Count > 0 && extension != ".shadergraph") { AssetFinderLOG.LogWarning($"AssetDatabase has {missingInFR2.Count} more dependencies than FR2 for '{assetPath}'. " + "This may indicate unsaved changes or new asset types not handled by FR2 parser."); // Add missing references to FR2's cache foreach (string missingGuid in missingInFR2) { AddUseGUID(missingGuid); AssetFinderLOG.Log($"Add missingGUID: {missingGuid} --> {AssetDatabase.GUIDToAssetPath(missingGuid)}"); } } } catch { AssetFinderLOG.LogWarning($"Failed to validate dependencies for {assetPath}"); } } internal void LoadYAML2() { if (!m_pathLoaded) LoadPathInfo(); if (!File.Exists(m_assetPath)) { state = AssetState.MISSING; return; } if (m_assetPath == "ProjectSettings/EditorBuildSettings.asset") { EditorBuildSettingsScene[] listScenes = EditorBuildSettings.scenes; foreach (EditorBuildSettingsScene scene in listScenes) { if (!scene.enabled) continue; string path = scene.path; string guid = AssetDatabase.AssetPathToGUID(path); AddUseGUID(guid, 0); // AssetFinderLOG.Log("AddScene: " + path); } } if (string.IsNullOrEmpty(extension)) { AssetFinderLOG.LogWarning($"Something wrong? <{m_extension}>"); } if (extension == ".spriteatlas") // check for force include in build { var atlasAsset = AssetDatabase.LoadAssetAtPath(m_assetPath); if (atlasAsset != null) { var so = new SerializedObject(atlasAsset); SerializedProperty prop = so.FindProperty("m_EditorData.bindAsDefault"); m_forceIncludeInBuild = prop.boolValue; } } AssetFinderParser.ReadContent(m_assetPath, AddUseGUID); } internal void LoadFolder() { if (!Directory.Exists(m_assetPath)) { state = AssetState.MISSING; return; } // do not analyse folders outside project if (!m_assetPath.StartsWith("Assets/")) return; try { string[] files = Directory.GetFiles(m_assetPath); string[] dirs = Directory.GetDirectories(m_assetPath); foreach (string f in files) { if (f.EndsWith(".meta", StringComparison.Ordinal)) continue; string fguid = AssetDatabase.AssetPathToGUID(f); if (string.IsNullOrEmpty(fguid)) continue; AddUseGUID(fguid); } foreach (string d in dirs) { string fguid = AssetDatabase.AssetPathToGUID(d); if (string.IsNullOrEmpty(fguid)) continue; AddUseGUID(fguid); } } catch (Exception e) { AssetFinderLOG.LogWarning("LoadFolder() error :: " + e + "\n" + assetPath); } finally { state = AssetState.MISSING; } } internal void LoadBinaryAsset() { ClearUseGUIDs(); UnityObject assetData = AssetDatabase.LoadAssetAtPath(m_assetPath, typeof(UnityObject)); if (assetData is GameObject go) { type = AssetType.MODEL; LoadGameObject(go); binaryLoaded += 10; } else if (assetData is TerrainData terrainData) { type = AssetType.TERRAIN; LoadTerrainData(terrainData); binaryLoaded += 20; } else if (assetData is LightingDataAsset lightAsset) { type = AssetType.LIGHTING_DATA; LoadLightingData(lightAsset); binaryLoaded += 20; } else { LoadSerialized(assetData); binaryLoaded++; } AssetFinderLOG.Log("LoadBinaryAsset :: " + assetData + ":" + type); if (binaryLoaded <= 30) return; binaryLoaded = 0; AssetFinderUnity.UnloadUnusedAssets(); } internal void LoadGameObject(GameObject go) { Component[] compList = go.GetComponentsInChildren(); for (var i = 0; i < compList.Length; i++) { LoadSerialized(compList[i]); } } internal void LoadSerialized(UnityObject target) { SerializedProperty[] props = AssetFinderUnity.xGetSerializedProperties(target, true); for (var i = 0; i < props.Length; i++) { if (props[i].propertyType != SerializedPropertyType.ObjectReference) continue; UnityObject refObj = props[i].objectReferenceValue; if (refObj == null) continue; string refGUID = AssetDatabase.AssetPathToGUID( AssetDatabase.GetAssetPath(refObj) ); AddUseGUID(refGUID); } } private void AddTextureGUID(SerializedProperty prop) { if (prop == null || prop.objectReferenceValue == null) return; string path = AssetDatabase.GetAssetPath(prop.objectReferenceValue); if (string.IsNullOrEmpty(path)) return; AddUseGUID(AssetDatabase.AssetPathToGUID(path)); } internal void LoadLightingData(LightingDataAsset asset) { foreach (Texture texture in AssetFinderLightmap.Read(asset)) { if (texture == null) continue; string path = AssetDatabase.GetAssetPath(texture); string assetGUID = AssetDatabase.AssetPathToGUID(path); if (!string.IsNullOrEmpty(assetGUID)) { AddUseGUID(assetGUID); } } } internal void LoadTerrainData(TerrainData terrain) { #if UNITY_2018_3_OR_NEWER TerrainLayer[] arr0 = terrain.terrainLayers; for (var i = 0; i < arr0.Length; i++) { string aPath = AssetDatabase.GetAssetPath(arr0[i]); string refGUID = AssetDatabase.AssetPathToGUID(aPath); AddUseGUID(refGUID); } #endif DetailPrototype[] arr = terrain.detailPrototypes; for (var i = 0; i < arr.Length; i++) { string aPath = AssetDatabase.GetAssetPath(arr[i].prototypeTexture); string refGUID = AssetDatabase.AssetPathToGUID(aPath); AddUseGUID(refGUID); } TreePrototype[] arr2 = terrain.treePrototypes; for (var i = 0; i < arr2.Length; i++) { string aPath = AssetDatabase.GetAssetPath(arr2[i].prefab); string refGUID = AssetDatabase.AssetPathToGUID(aPath); AddUseGUID(refGUID); } AssetFinderTerrain.TerrainTextureData[] arr3 = AssetFinderTerrain.GetTerrainTextureDatas(terrain); for (var i = 0; i < arr3.Length; i++) { AssetFinderTerrain.TerrainTextureData texs = arr3[i]; for (var k = 0; k < texs.textures.Length; k++) { Texture2D tex = texs.textures[k]; if (tex == null) continue; string aPath = AssetDatabase.GetAssetPath(tex); if (string.IsNullOrEmpty(aPath)) continue; string refGUID = AssetDatabase.AssetPathToGUID(aPath); if (string.IsNullOrEmpty(refGUID)) continue; AddUseGUID(refGUID); } } } internal static void ClearLog() { if (shouldWriteImportLog) { File.WriteAllText(logPath, string.Empty); } else { if (File.Exists(logPath)) File.Delete(logPath); } scanStartTime = DateTime.Now; } internal static void WriteTotalScanTime() { if (!shouldWriteImportLog) return; double totalScanTime = (DateTime.Now - scanStartTime).TotalSeconds; File.AppendAllText(logPath, $"\nTotal scan time: {totalScanTime} seconds\n"); } private void ClearUseGUIDs() { // AssetFinderLOG.Log("ClearUseGUIDs: " + assetPath); UseGUIDs.Clear(); UseGUIDsList.Clear(); } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderAsset.ContentLoader.cs.meta ================================================ fileFormatVersion: 2 guid: 8b4f01c105762d742adedeca5785b5ca MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderAsset.Drawing.cs ================================================ using System; using System.IO; using UnityEditor; using UnityEngine; using UnityObject = UnityEngine.Object; namespace VirtueSky.AssetFinder.Editor { internal partial class AssetFinderAsset { // ----------------------------- UI DRAWING & USER ACTIONS --------------------------------------- internal class AssetFinderAssetDrawConfig { public bool highlight; public bool drawPath = true; public bool showFileSize = true; public bool showABName = false; public bool showAtlasName = false; public bool showUsageIcon = true; public IWindow window = null; public bool drawExtension = true; public Action onShowDetails = null; public AssetFinderAssetDrawConfig( bool highlight, bool drawPath = true, bool showFileSize = true, bool showABName = false, bool showAtlasName = false, bool showUsageIcon = true, IWindow window = null, bool drawExtension = true, Action onShowDetails = null) { this.highlight = highlight; this.drawPath = drawPath; this.showFileSize = showFileSize; this.showABName = showABName; this.showAtlasName = showAtlasName; this.showUsageIcon = showUsageIcon; this.window = window; this.drawExtension = drawExtension; this.onShowDetails = onShowDetails; } } internal float Draw( Rect r, AssetFinderAssetDrawConfig cfg ) { Rect rowRect = new Rect(r.x, r.y, r.width, AssetFinderTheme.Current.TreeItemHeight); bool isHover = rowRect.Contains(Event.current.mousePosition); bool singleLine = r.height <= 18f; float rw = r.width; bool selected = AssetFinderBookmark.Contains(guid); r.height = AssetFinderTheme.Current.TreeItemHeight; bool hasMouse = (Event.current.type == EventType.MouseUp) && r.Contains(Event.current.mousePosition); if (hasMouse && (Event.current.button == 1)) { var menu = new GenericMenu(); if (m_extension == ".prefab") menu.AddItem(AssetFinderGUIContent.FromString("Edit in Scene"), false, EditPrefab); menu.AddItem(AssetFinderGUIContent.FromString("Open"), false, Open); menu.AddItem(AssetFinderGUIContent.FromString("Ping"), false, Ping); #if UNITY_2022_3_OR_NEWER menu.AddItem(AssetFinderGUIContent.FromString("Properties..."), false, OpenProperties); #endif menu.AddItem(AssetFinderGUIContent.FromString(guid), false, CopyGUID); //menu.AddItem(AssetFinderGUIContent.FromString("Select in Project Panel"), false, Select); menu.AddSeparator(string.Empty); menu.AddItem(AssetFinderGUIContent.FromString("Copy path"), false, CopyAssetPath); menu.AddItem(AssetFinderGUIContent.FromString("Copy full path"), false, CopyAssetPathFull); menu.ShowAsContext(); Event.current.Use(); } if (IsMissing) { if (!singleLine) r.y += 16f; if (Event.current.type != EventType.Repaint) return 0; GUI.Label(r, AssetFinderGUIContent.FromString(guid), EditorStyles.whiteBoldLabel); return 0; } Rect iconRect = GUI2.LeftRect(16f, ref r); GUI2.LeftRect(2f, ref r); if (Event.current.type == EventType.Repaint) { Texture icon = AssetDatabase.GetCachedIcon(m_assetPath); if (icon != null) GUI.DrawTexture(iconRect, icon, ScaleMode.ScaleToFit); } if ((Event.current.type == EventType.MouseDown) && (Event.current.button == 0)) { Rect pingRect = iconRect; //AssetFinderSetting.PingRow ? new Rect(0, r.y, r.x + r.width, r.height) : if (pingRect.Contains(Event.current.mousePosition)) { if (Event.current.control || Event.current.command) { if (selected) { RemoveFromSelection(); } else { AddToSelection(); } if (cfg.window != null) cfg.window.Repaint(); } else if (Event.current.clickCount == 2) { Open(); Event.current.Use(); } else { Ping(); } } } if (isHover) { if (cfg.onShowDetails != null) { r.xMax -= 10f; var (detailRect, flex) = r.ExtractRight(22f); if (GUI.Button(detailRect, new GUIContent("...", "Show Details"), EditorStyles.miniButton)) { cfg.onShowDetails?.Invoke(); } r = flex; } #if UNITY_2022_3_OR_NEWER var (propRect, flex1) = r.ExtractRight(22f); if (GUI.Button(propRect, new GUIContent("P", "Open Properties"), EditorStyles.miniButton)) { OpenProperties(); } r = flex1; #endif } if (Event.current.type != EventType.Repaint) return 0; if ((UsedByMap != null) && (UsedByMap.Count > 0)) { GUIContent str = AssetFinderGUIContent.FromInt(UsedByMap.Count); Rect countRect = iconRect; countRect.x -= 16f; countRect.xMin = -10f; GUI.Label(countRect, str, GUI2.miniLabelAlignRight); } float pathW = cfg.drawPath && !string.IsNullOrEmpty(assetFolder) ? EditorStyles.miniLabel.CalcSize(AssetFinderGUIContent.FromString(assetFolder)).x : 8f; float nameW = cfg.drawPath ? EditorStyles.boldLabel.CalcSize(AssetFinderGUIContent.FromString(assetName)).x : EditorStyles.label.CalcSize(AssetFinderGUIContent.FromString(assetName)).x; float extW = string.IsNullOrEmpty(extension) ? 0f : EditorStyles.miniLabel.CalcSize(AssetFinderGUIContent.FromString(extension)).x; Color cc = GUI.skin.settings.selectionColor; if (singleLine) { Rect lbRect = GUI2.LeftRect(pathW + nameW + extW, ref r); if (selected) { Color c1 = GUI.color; GUI.color = cc; GUI.DrawTexture(lbRect, EditorGUIUtility.whiteTexture); GUI.color = c1; } if (cfg.drawPath) { if (!string.IsNullOrEmpty(assetFolder)) { Color c2 = GUI.color; GUI.color = new Color(c2.r, c2.g, c2.b, c2.a * 0.5f); GUI.Label(GUI2.LeftRect(pathW, ref lbRect), AssetFinderGUIContent.FromString(assetFolder), EditorStyles.miniLabel); GUI.color = c2; } GUI.Label(lbRect, AssetFinderGUIContent.FromString(assetName), EditorStyles.boldLabel); } else { GUI.Label(lbRect, AssetFinderGUIContent.FromString(assetName), EditorStyles.label); } lbRect.xMin += nameW - 2f; lbRect.y += 1f; if (!string.IsNullOrEmpty(extension) && cfg.drawExtension) { Color c3 = GUI.color; GUI.color = new Color(c3.r, c3.g, c3.b, c3.a * 0.7f); GUI.Label(lbRect, AssetFinderGUIContent.FromString(extension), EditorStyles.miniLabel); GUI.color = c3; } } else { if (cfg.drawPath) GUI.Label(new Rect(r.x, r.y + 16f, r.width, r.height), AssetFinderGUIContent.FromString(m_assetFolder), EditorStyles.miniLabel); Rect lbRect = GUI2.LeftRect(nameW, ref r); if (selected) GUI2.Rect(lbRect, cc); GUI.Label(lbRect, AssetFinderGUIContent.FromString(assetName), EditorStyles.boldLabel); } Rect rr = GUI2.RightRect(10f, ref r); if (cfg.highlight) { rr.xMin += 2f; rr.width = 1f; GUI2.Rect(rr, GUI2.darkGreen); } Color c = GUI.color; GUI.color = new Color(c.r, c.g, c.b, c.a * 0.5f); // (Properties button drawn earlier to receive click events) if (cfg.showFileSize) { Rect fsRect = GUI2.RightRect(40f, ref r); if (fileSizeText == null) fileSizeText = AssetFinderGUIContent.FromString(AssetFinderHelper.GetfileSizeString(fileSize)); GUI.Label(fsRect, fileSizeText, GUI2.miniLabelAlignRight); } if (!string.IsNullOrEmpty(m_addressable)) { Rect adRect = GUI2.RightRect(100f, ref r); GUI.Label(adRect, AssetFinderGUIContent.FromString(m_addressable), GUI2.miniLabelAlignRight); } if (cfg.showUsageIcon && (HashUsedByClassesIds != null)) { foreach (int item in HashUsedByClassesIds) { if (!AssetFinderUnity.HashClassesNormal.ContainsKey(item)) continue; string name = AssetFinderUnity.HashClassesNormal[item]; if (!HashClasses.TryGetValue(item, out Type t)) { t = AssetFinderUnity.GetType(name); HashClasses.Add(item, t); } bool isExisted = cacheImage.TryGetValue(name, out GUIContent content); if (content == null) { content = t == null ? GUIContent.none : AssetFinderGUIContent.FromType(t, name); } if (!isExisted) { cacheImage.Add(name, content); } else { cacheImage[name] = content; } if (content != null) { try { GUI.Label(GUI2.RightRect(15f, ref r), content, GUI2.miniLabelAlignRight); } catch (Exception e) { AssetFinderLOG.LogWarning(e); } } } } if (cfg.showAtlasName) { GUI2.RightRect(10f, ref r); Rect abRect = GUI2.RightRect(120f, ref r); if (!string.IsNullOrEmpty(m_atlas)) GUI.Label(abRect, AssetFinderGUIContent.FromString(m_atlas), GUI2.miniLabelAlignRight); } if (cfg.showABName) { GUI2.RightRect(10f, ref r); Rect abRect = GUI2.RightRect(100f, ref r); if (!string.IsNullOrEmpty(m_assetbundle)) GUI.Label(abRect, AssetFinderGUIContent.FromString(m_assetbundle), GUI2.miniLabelAlignRight); } if (true) { GUI2.RightRect(10f, ref r); Rect abRect = GUI2.RightRect(100f, ref r); if (!string.IsNullOrEmpty(m_addressable)) GUI.Label(abRect, AssetFinderGUIContent.FromString(m_addressable), GUI2.miniLabelAlignRight); } GUI.color = c; if (Event.current.type == EventType.Repaint) return rw < pathW + nameW ? 32f : 18f; return r.height; } internal GenericMenu AddArray( GenericMenu menu, System.Collections.Generic.List list, string prefix, string title, string emptyTitle, bool showAsset, int max = 10) { menu.AddItem(AssetFinderGUIContent.FromString(emptyTitle), true, null); return menu; } internal void CopyGUID() { EditorGUIUtility.systemCopyBuffer = guid; Debug.Log(guid); } internal void CopyName() { EditorGUIUtility.systemCopyBuffer = m_assetName; Debug.Log(m_assetName); } internal void CopyAssetPath() { EditorGUIUtility.systemCopyBuffer = m_assetPath; Debug.Log(m_assetPath); } internal void CopyAssetPathFull() { string fullName = new FileInfo(m_assetPath).FullName; EditorGUIUtility.systemCopyBuffer = fullName; Debug.Log(fullName); } internal void RemoveFromSelection() { if (AssetFinderBookmark.Contains(guid)) AssetFinderBookmark.Remove(guid); } internal void AddToSelection() { if (!AssetFinderBookmark.Contains(guid)) AssetFinderBookmark.Add(guid); } internal void Ping() { if (EditorWindow.focusedWindow is AssetFinderWindowAll fr2Window) { fr2Window.smartLock.SetPingLockState(AssetFinderSmartLock.PingLockState.Asset); } EditorApplication.delayCall += () => { var asset = AssetDatabase.LoadAssetAtPath(m_assetPath, typeof(UnityObject)); if (asset != null) { EditorGUIUtility.PingObject(asset); } }; // Only use event if it exists (not null when called from context menu) if (Event.current != null) { Event.current.Use(); } } internal void Open() { AssetDatabase.OpenAsset( AssetDatabase.LoadAssetAtPath(m_assetPath, typeof(UnityObject)) ); } internal void OpenProperties() { #if UNITY_2022_3_OR_NEWER var obj = AssetDatabase.LoadAssetAtPath(m_assetPath, typeof(UnityObject)); if (obj != null) { EditorUtility.OpenPropertyEditor(obj); } #endif } internal void EditPrefab() { UnityObject prefab = AssetDatabase.LoadAssetAtPath(m_assetPath, typeof(UnityObject)); UnityObject.Instantiate(prefab); } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderAsset.Drawing.cs.meta ================================================ fileFormatVersion: 2 guid: 92421bd9e4cef8a4e969c1da1c6f6769 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderAsset.FileInfo.cs ================================================ using System; using System.IO; using UnityEditor; using UnityEngine; namespace VirtueSky.AssetFinder.Editor { internal partial class AssetFinderAsset { // ----------------------- FILE INFO ------------------------ public bool fileInfoDirty => type == AssetType.UNKNOWN || m_fileInfoReadTS <= m_assetChangeTS; public bool fileContentDirty => (m_fileWriteTS != m_cachefileWriteTS) && !isBuiltIn; public bool isDirty => (fileInfoDirty || fileContentDirty) && !isBuiltIn; public bool isBuiltIn => type == AssetType.BUILT_IN; public bool hasBeenScanned => m_cachefileWriteTS > 0 || isBuiltIn; internal string fileInfoHash => LoadFileInfo().m_fileInfoHash; internal long fileSize => LoadFileInfo().m_fileSize; public string AtlasName => LoadFileInfo().m_atlas; public string AssetBundleName => LoadFileInfo().m_assetbundle; public string AddressableName => LoadFileInfo().m_addressable; private bool ExistOnDisk() { if (isBuiltIn) return true; if (IsMissing) return false; // asset not exist - no need to check FileSystem! if (type == AssetType.FOLDER || type == AssetType.UNKNOWN) { if (Directory.Exists(m_assetPath)) { if (type == AssetType.UNKNOWN) type = AssetType.FOLDER; return true; } if (type == AssetType.FOLDER) return false; } // must be file here if (!File.Exists(m_assetPath)) return false; if (type == AssetType.UNKNOWN) GuessAssetType(); return true; } internal AssetFinderAsset LoadFileInfo() { if (!fileInfoDirty) return this; if (string.IsNullOrEmpty(m_assetPath)) LoadPathInfo(); // always reload Path Info m_fileInfoReadTS = AssetFinderUnity.Epoch(DateTime.Now); if (isBuiltIn) return this; if (IsMissing) { return this; } if (!ExistOnDisk()) { state = AssetState.MISSING; return this; } if (type == AssetType.FOLDER) return this; // nothing to read Type assetType = AssetDatabase.GetMainAssetTypeAtPath(m_assetPath); if (assetType == typeof(AssetFinderCache)) return this; var info = new FileInfo(m_assetPath); m_fileSize = info.Length; m_fileInfoHash = info.Length + info.Extension; m_addressable = AssetFinderUnity.GetAddressable(guid); m_assetbundle = AssetDatabase.GetImplicitAssetBundleName(m_assetPath); if (assetType == typeof(Texture2D)) { AssetImporter importer = AssetImporter.GetAtPath(m_assetPath); if (importer is TextureImporter tImporter) { #pragma warning disable CS0618 if (tImporter.qualifiesForSpritePacking) m_atlas = tImporter.spritePackingTag; #pragma warning restore CS0618 } } // check if file content changed var metaInfo = new FileInfo(m_assetPath + ".meta"); int assetTime = AssetFinderUnity.Epoch(info.LastWriteTime); int metaTime = AssetFinderUnity.Epoch(metaInfo.LastWriteTime); // update fileChangeTimeStamp m_fileWriteTS = Mathf.Max(metaTime, assetTime); return this; } internal void GuessAssetType() { var ext = extension.ToLowerInvariant(); if (SCRIPT_EXTENSIONS.Contains(ext)) { type = AssetType.SCRIPT; } else if (REFERENCABLE_EXTENSIONS.Contains(ext)) { bool isUnity = ext == ".unity"; type = isUnity ? AssetType.SCENE : AssetType.REFERENCABLE; if (ext == ".asset" || isUnity || ext == ".spriteatlas") { var buffer = new byte[5]; FileStream stream = null; try { stream = File.OpenRead(m_assetPath); stream.Read(buffer, 0, 5); stream.Close(); } #if AssetFinderDEBUG catch (Exception e) { AssetFinderLOG.LogWarning("Guess Asset Type error :: " + e + "\n" + m_assetPath); #else catch { #endif if (stream != null) stream.Close(); state = AssetState.MISSING; return; } finally { if (stream != null) stream.Close(); } var str = string.Empty; foreach (byte t in buffer) { str += (char)t; } if (str != "%YAML") type = AssetType.BINARY_ASSET; } } else if (REFERENCABLE_JSON.Contains(ext) || UI_TOOLKIT.Contains(ext)) { type = AssetType.REFERENCABLE; } else if (REFERENCABLE_META.Contains(ext)) { type = AssetType.REFERENCABLE; } else if (ext == ".fbx") { type = AssetType.MODEL; } else if (ext == ".dll") { type = AssetType.DLL; } else { type = AssetType.NON_READABLE; } } internal void MarkAsDirty(bool isMoved = true, bool force = false) { if (isMoved) { string newPath = AssetDatabase.GUIDToAssetPath(guid); if (newPath != m_assetPath) { m_pathLoaded = false; m_assetPath = newPath; } } state = AssetState.CACHE; m_assetChangeTS = AssetFinderUnity.Epoch(DateTime.Now); // re-read FileInfo if (force) m_cachefileWriteTS = 0; } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderAsset.FileInfo.cs.meta ================================================ fileFormatVersion: 2 guid: def6a6c199d5b5c44b9920f983b64d92 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderAsset.GuidManager.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using UnityEditor; namespace VirtueSky.AssetFinder.Editor { internal partial class AssetFinderAsset { // ----------------------------- GUID MANAGEMENT --------------------------------------- public Dictionary> UseGUIDs { get { if (_UseGUIDs != null) return _UseGUIDs; _UseGUIDs = new Dictionary>(UseGUIDsList.Count); for (var i = 0; i < UseGUIDsList.Count; i++) { string guid = UseGUIDsList[i].guid; if (_UseGUIDs.ContainsKey(guid)) { for (var j = 0; j < UseGUIDsList[i].ids.Count; j++) { long val = UseGUIDsList[i].ids[j]; if (_UseGUIDs[guid].Contains(val)) continue; _UseGUIDs[guid].Add(UseGUIDsList[i].ids[j]); } } else { _UseGUIDs.Add(guid, new HashSet(UseGUIDsList[i].ids)); } } return _UseGUIDs; } } internal void AddUseGUID(string fguid, long fFileId = -1) { AddUseGUID(fguid, fFileId, true); } internal void AddUseGUID(string fguid, long fFileId, bool checkExist) { // if (checkExist && UseGUIDs.ContainsKey(fguid)) return; if (!IsValidGUID(fguid)) return; if (!UseGUIDs.ContainsKey(fguid)) { UseGUIDsList.Add(new Classes { guid = fguid, ids = new List() }); UseGUIDs.Add(fguid, new HashSet()); } if (fFileId == -1) return; if (UseGUIDs[fguid].Contains(fFileId)) return; UseGUIDs[fguid].Add(fFileId); Classes i = UseGUIDsList.FirstOrDefault(x => x.guid == fguid); if (i != null) i.ids.Add(fFileId); } public void AddUsedBy(string guid, AssetFinderAsset asset) { if (UsedByMap.ContainsKey(guid)) return; if (guid == this.guid) { return; } UsedByMap.Add(guid, asset); if (HashUsedByClassesIds == null) HashUsedByClassesIds = new HashSet(); if (asset.UseGUIDs.TryGetValue(this.guid, out HashSet output)) { foreach (int item in output) { HashUsedByClassesIds.Add(item); } } } public int UsageCount() { return UsedByMap.Count; } public int UseGUIDsCount { get { // Return 0 for ignored assets and package assets because we don't scan their content if (IsExcluded || inPackages) { return 0; } return UseGUIDs.Count; } } public string DebugUseGUID() { return $"{guid} : {assetPath}\n{string.Join("\n", UseGUIDsList.Select(item => item.guid).ToArray())}"; } internal static bool IsValidGUID(string guid) { return AssetDatabase.GUIDToAssetPath(guid) != AssetFinderCache.CachePath; // just skip AssetFinderCache asset } internal static List FindUsageGUIDs(AssetFinderAsset asset, bool includeScriptSymbols) { var result = new HashSet(); if (asset == null) { AssetFinderLOG.LogWarning("Asset invalid : " + asset.m_assetName); return result.ToList(); } foreach (KeyValuePair> item in asset.UseGUIDs) { result.Add(item.Key); } return result.ToList(); } internal static List FindUsedByGUIDs(AssetFinderAsset asset) { return asset.UsedByMap.Keys.ToList(); } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderAsset.GuidManager.cs.meta ================================================ fileFormatVersion: 2 guid: 9bb02cbb695900d4b91c00fbee372c7d MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderAsset.PathInfo.cs ================================================ using System; using System.Globalization; using UnityEditor; using UnityEngine; namespace VirtueSky.AssetFinder.Editor { internal partial class AssetFinderAsset { // ----------------------- PATH INFO ------------------------ [NonSerialized] private string m_assetFolder; [NonSerialized] private string m_assetName; [NonSerialized] private string m_assetPath; [NonSerialized] private string m_extension; [NonSerialized] private bool m_inEditor; [NonSerialized] private bool m_inPackage; [NonSerialized] private bool m_inPlugins; [NonSerialized] private bool m_inResources; [NonSerialized] private bool m_inStreamingAsset; [NonSerialized] private bool m_pathLoaded; public string assetName => LoadPathInfo().m_assetName; public string assetPath { get { if (!string.IsNullOrEmpty(m_assetPath)) return m_assetPath; m_assetPath = AssetDatabase.GUIDToAssetPath(guid); if (string.IsNullOrEmpty(m_assetPath)) state = AssetState.MISSING; return m_assetPath; } } public string parentFolderPath => LoadPathInfo().m_assetFolder; public string assetFolder => LoadPathInfo().m_assetFolder; public string extension => LoadPathInfo().m_extension; public bool inEditor => LoadPathInfo().m_inEditor; public bool inPlugins => LoadPathInfo().m_inPlugins; public bool inPackages => LoadPathInfo().m_inPackage; public bool inResources => LoadPathInfo().m_inResources; public bool inStreamingAsset => LoadPathInfo().m_inStreamingAsset; internal bool IsExcluded { get { if (excludeTS >= ignoreTS) return _isExcluded; excludeTS = ignoreTS; _isExcluded = false; var h = AssetFinderSetting.IgnoreAsset; foreach (string item in h) { if (!m_assetPath.StartsWith(item, false, CultureInfo.InvariantCulture)) continue; _isExcluded = true; return true; } return false; } } public AssetFinderAsset LoadPathInfo() { if (m_pathLoaded) return this; m_pathLoaded = true; m_assetPath = AssetDatabase.GUIDToAssetPath(guid); if (string.IsNullOrEmpty(assetPath)) { state = AssetState.MISSING; return this; } // #if AssetFinderDEBUG // AssetFinderLOG.Log("LoadPathInfo ... " + fileInfoHash + ":" + AssetDatabase.GUIDToAssetPath(guid)); // #endif AssetFinderUnity.SplitPath(m_assetPath, out m_assetName, out m_extension, out m_assetFolder); if (m_assetFolder.StartsWith("Assets/")) { m_assetFolder = m_assetFolder.Substring(7); } else if (!AssetFinderUnity.StringStartsWith(m_assetPath,"Project Settings/", "Library/")) m_assetFolder = "built-in/"; m_inEditor = m_assetPath.Contains("/Editor/") || m_assetPath.Contains("/Editor Default Resources/"); m_inResources = m_assetPath.Contains("/Resources/"); m_inStreamingAsset = m_assetPath.Contains("/StreamingAssets/"); m_inPlugins = m_assetPath.Contains("/Plugins/"); m_inPackage = m_assetPath.StartsWith("Packages/"); return this; } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderAsset.PathInfo.cs.meta ================================================ fileFormatVersion: 2 guid: aeaa48e4ac2b35e43951fa13a606b81c MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderAsset.cs ================================================ #if AssetFinderADDRESSABLE using UnityEditor.AddressableAssets; using UnityEngine.AddressableAssets; #endif using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; using System.Text; using UnityEditor; using UnityEngine; using UnityEngine.Serialization; using UnityObject = UnityEngine.Object; namespace VirtueSky.AssetFinder.Editor { [Serializable] internal partial class AssetFinderAsset { // Constants moved to AssetFinderAsset.Constants.cs // ----------------------------- DRAW --------------------------------------- [SerializeField] public string guid; // Need to read FileInfo: soft-cache (always re-read when needed) [FormerlySerializedAs("type2")] [SerializeField] public AssetType type; [SerializeField] private string m_fileInfoHash; [SerializeField] private string m_assetbundle; [SerializeField] private string m_addressable; [SerializeField] private string m_atlas; [SerializeField] private long m_fileSize; [SerializeField] private int m_assetChangeTS; // Realtime when asset changed (trigger by import asset operation) [SerializeField] private int m_fileInfoReadTS; // Realtime when asset being read [SerializeField] private int m_fileWriteTS; // file's lastModification (file content + meta) [SerializeField] private int m_cachefileWriteTS; // file's lastModification at the time the content being read [SerializeField] private bool m_forceIncludeInBuild; [SerializeField] internal int refreshStamp; // use to check if asset has been deleted (refreshStamp not updated) [SerializeField] internal List UseGUIDsList = new List(); private bool _isExcluded; private Dictionary> _UseGUIDs; private float excludeTS; // ----------------------------- DRAW --------------------------------------- [NonSerialized] private GUIContent fileSizeText; internal HashSet HashUsedByClassesIds = new HashSet(); // Path info moved to AssetFinderAsset.PathInfo.cs // Do not cache [NonSerialized] internal AssetState state; internal Dictionary UsedByMap = new Dictionary(); public AssetFinderAsset(string guid) { this.guid = guid; type = BUILT_IN_ASSETS.Contains(guid) ? AssetType.BUILT_IN : AssetType.UNKNOWN; } public bool forcedIncludedInBuild => m_forceIncludeInBuild; // ----------------------- TYPE INFO ------------------------ internal bool IsFolder => type == AssetType.FOLDER; internal bool IsScript => type == AssetType.SCRIPT; internal bool IsMissing => (state == AssetState.MISSING) && !isBuiltIn; internal bool IsReferencable => type == AssetType.REFERENCABLE || type == AssetType.SCENE; internal bool IsBinaryAsset => type == AssetType.BINARY_ASSET || type == AssetType.MODEL || type == AssetType.TERRAIN || type == AssetType.LIGHTING_DATA; // ------------------------------- GETTERS ----------------------------- internal bool IsCriticalAsset() { // Packages assets are always non-critical if (string.IsNullOrEmpty(assetPath)) // && assetPath.StartsWith("Packages/") { return false; } if (AssetDatabase.IsValidFolder(assetPath)) { return false; } if (type == AssetType.UNKNOWN) GuessAssetType(); // Fast checks on asset type switch (type) { case AssetType.REFERENCABLE: case AssetType.SCENE: case AssetType.BINARY_ASSET: case AssetType.MODEL: case AssetType.TERRAIN: case AssetType.LIGHTING_DATA: return true; case AssetType.FOLDER: case AssetType.SCRIPT: case AssetType.DLL: case AssetType.NON_READABLE: { // if (assetPath.Contains(".png")) AssetFinderLOG.LogWarning($"Wrong assetType? {type}"); return false; } } if (string.IsNullOrEmpty(extension)) { // if (assetPath.Contains(".png")) AssetFinderLOG.LogWarning($"Wrong extensions? {extension}"); return false; } var result = !NON_REFERENCE_EXTENSIONS.Contains(extension); // if (assetPath.Contains(".png")) AssetFinderLOG.LogWarning($"Result = {result}"); return result; } // GUID management methods moved to AssetFinderAsset.GuidManager.cs public override string ToString() { return $"AssetFinderAsset[{m_assetName}]"; } // AddUseGUID methods moved to AssetFinderAsset.GuidManager.cs // ----------------------------- STATIC --------------------------------------- internal static int SortByExtension(AssetFinderAsset a1, AssetFinderAsset a2) { if (a1 == null) return -1; if (a2 == null) return 1; int result = string.Compare(a1.m_extension, a2.m_extension, StringComparison.Ordinal); return result == 0 ? string.Compare(a1.m_assetName, a2.m_assetName, StringComparison.Ordinal) : result; } internal static List FindUsage(AssetFinderAsset asset) { if (asset == null) return null; List refs = AssetFinderCache.Api.FindAssets(asset.UseGUIDs.Keys.ToArray(), true); return refs; } internal static List FindUsedBy(AssetFinderAsset asset) { return asset.UsedByMap.Values.ToList(); } // ----------------------------- REPLACE GUIDS --------------------------------------- internal bool ReplaceReference(string fromGUID, string toGUID, TerrainData terrain = null) { if (IsMissing) return false; if (IsReferencable) { if (!File.Exists(m_assetPath)) { state = AssetState.MISSING; return false; } try { string text = File.ReadAllText(m_assetPath).Replace("\r", "\n"); File.WriteAllText(m_assetPath, text.Replace(fromGUID, toGUID)); return true; } catch (Exception e) { state = AssetState.MISSING; AssetFinderLOG.LogWarning("Replace Reference error :: " + e + "\n" + m_assetPath); } return false; } if (type == AssetType.TERRAIN) { var fromObj = AssetFinderUnity.LoadAssetWithGUID(fromGUID); var toObj = AssetFinderUnity.LoadAssetWithGUID(toGUID); var found = 0; if (fromObj is Texture2D tex) { DetailPrototype[] arr = terrain.detailPrototypes; for (var i = 0; i < arr.Length; i++) { if (arr[i].prototypeTexture != tex) continue; found++; arr[i].prototypeTexture = (Texture2D)toObj; } terrain.detailPrototypes = arr; AssetFinderTerrain.ReplaceTerrainTextureDatas(terrain, tex, (Texture2D)toObj); } if (fromObj is GameObject go) { TreePrototype[] arr2 = terrain.treePrototypes; for (var i = 0; i < arr2.Length; i++) { if (arr2[i].prefab != go) continue; found++; arr2[i].prefab = (GameObject)toObj; } terrain.treePrototypes = arr2; } return found > 0; } AssetFinderLOG.LogWarning("Something wrong, should never be here - Ignored <" + m_assetPath + "> : not a readable type, can not replace ! " + type); return false; } internal string ReplaceFileIdIfNeeded(string line, long toFileId) { const string FileID = "fileID: "; int index = line.IndexOf(FileID, StringComparison.Ordinal); if (index < 0 || toFileId <= 0) return line; int startIndex = index + FileID.Length; int endIndex = line.IndexOf(',', startIndex); if (endIndex > startIndex) { string fromFileId = line.Substring(startIndex, endIndex - startIndex); if (long.TryParse(fromFileId, out long fileType) && fileType.ToString().StartsWith(toFileId.ToString().Substring(0, 3))) { AssetFinderLOG.Log($"ReplaceReference: fromFileId {fromFileId} to File Id {toFileId}"); return line.Replace(fromFileId, toFileId.ToString()); } AssetFinderLOG.LogWarning($"[Skip] Difference file type: {fromFileId} -> {toFileId}"); } else { AssetFinderLOG.LogWarning("Cannot parse fileID in the line."); } return line; } internal bool ReplaceReference(string fromGUID, string toGUID, long toFileId, TerrainData terrain = null) { if (IsMissing) { return false; } if (IsReferencable) { if (!File.Exists(m_assetPath)) { state = AssetState.MISSING; return false; } try { var sb = new StringBuilder(); string text = File.ReadAllText(assetPath); var currentIndex = 0; while (currentIndex < text.Length) { int lineEndIndex = text.IndexOfAny(new[] { '\r', '\n' }, currentIndex); if (lineEndIndex == -1) { lineEndIndex = text.Length; } string line = text.Substring(currentIndex, lineEndIndex - currentIndex); // Check if the line contains the GUID and possibly the fileID if (line.Contains(fromGUID)) { line = ReplaceFileIdIfNeeded(line, toFileId); line = line.Replace(fromGUID, toGUID); } sb.Append(line); // Skip through any EOL characters while (lineEndIndex < text.Length) { char c = text[lineEndIndex]; if (c == '\r' || c == '\n') { sb.Append(c); lineEndIndex++; } break; } currentIndex = lineEndIndex; } File.WriteAllText(assetPath, sb.ToString()); //AssetDatabase.ImportAsset(assetPath, ImportAssetOptions.Default); return true; } catch (Exception e) { state = AssetState.MISSING; AssetFinderLOG.LogWarning("Replace Reference error :: " + e + "\n" + m_assetPath); } return false; } if (type == AssetType.TERRAIN) { var fromObj = AssetFinderUnity.LoadAssetWithGUID(fromGUID); var toObj = AssetFinderUnity.LoadAssetWithGUID(toGUID); var found = 0; // var terrain = AssetDatabase.LoadAssetAtPath(assetPath, typeof(Object)) as TerrainData; if (fromObj is Texture2D) { DetailPrototype[] arr = terrain.detailPrototypes; for (var i = 0; i < arr.Length; i++) { if (arr[i].prototypeTexture == (Texture2D)fromObj) { found++; arr[i].prototypeTexture = (Texture2D)toObj; } } terrain.detailPrototypes = arr; AssetFinderTerrain.ReplaceTerrainTextureDatas(terrain, (Texture2D)fromObj, (Texture2D)toObj); } if (fromObj is GameObject go) { TreePrototype[] arr2 = terrain.treePrototypes; for (var i = 0; i < arr2.Length; i++) { if (arr2[i].prefab != go) continue; found++; arr2[i].prefab = (GameObject)toObj; } terrain.treePrototypes = arr2; } // EditorUtility.SetDirty(terrain); // AssetDatabase.SaveAssets(); // AssetFinderUnity.UnloadUnusedAssets(); return found > 0; } AssetFinderLOG.LogWarning("Something wrong, should never be here - Ignored <" + m_assetPath + "> : not a readable type, can not replace ! " + type); return false; } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderAsset.cs.meta ================================================ fileFormatVersion: 2 guid: c543b7730e7086043a9e90ab6713e909 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderAutoRefreshMode.cs ================================================ namespace VirtueSky.AssetFinder.Editor { public enum AssetFinderAutoRefreshMode { On, // Auto refresh enabled Off, // Auto refresh disabled by user AutoOff // Auto refresh automatically disabled due to frequent changes } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderAutoRefreshMode.cs.meta ================================================ fileFormatVersion: 2 guid: fcfe60c37601b3e419b544b3cf969b50 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderCache.AssetSearch.cs ================================================ // this file has been deleted ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderCache.AssetSearch.cs.meta ================================================ fileFormatVersion: 2 guid: 8e7f2fbc78d4980488c970632c6aaab2 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderCache.AsyncProcessor.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using UnityEditor; using UnityEngine; namespace VirtueSky.AssetFinder.Editor { internal partial class AssetFinderCache { internal static void DelayCheck4Changes() { EditorApplication.update -= Check; EditorApplication.update += Check; } private static void Check() { if (EditorApplication.isCompiling || EditorApplication.isUpdating || AssetFinderSettingExt.disable) { delayCounter = 100; return; } if (Api == null) return; if (delayCounter-- > 0) return; EditorApplication.update -= Check; Api.IncrementalRefresh(); } internal void Check4Changes(bool force) { if (EditorApplication.isCompiling || EditorApplication.isUpdating || AssetFinderSettingExt.disable) { DelayCheck4Changes(); return; } ready = false; ReadFromProject(force); // AssetFinderLOG.Log($"After ReadFromProject :: WorkCount: {workCount}, AssetMap: {AssetMap.Count}, AssetList: {AssetList.Count}"); Check4Work(); } internal void RefreshUsedByOnlyFromCache() { if (EditorApplication.isCompiling || EditorApplication.isUpdating || AssetFinderSettingExt.disable) return; ready = false; ReadFromCache(); workCount = 0; if (queueLoadContent != null) queueLoadContent.Clear(); Check4Usage(); } internal void IncrementalRefresh() { if (EditorApplication.isCompiling || EditorApplication.isUpdating || AssetFinderSettingExt.disable) { DelayCheck4Changes(); return; } ready = false; workCount = 0; if (queueLoadContent != null) queueLoadContent.Clear(); if (AssetMap == null) { Debug.LogWarning("Why should the AssetMap == null? The FR2 cache might be incompatible?"); return; } // CRITICAL FIX: First check for new assets that were added to the project var paths = AssetDatabase.GetAllAssetPaths(); cacheStamp++; // Check for new assets foreach (string p in paths) { bool isValid = AssetFinderUnity.StringStartsWith(p, "Assets/", "Packages/", "Library/", "ProjectSettings/"); if (!isValid) continue; string guid = AssetDatabase.AssetPathToGUID(p); if (!AssetFinderAsset.IsValidGUID(guid)) continue; if (!AssetMap.TryGetValue(guid, out AssetFinderAsset asset)) { // New asset detected - add it AddAsset(guid, false); // Don't force, let auto refresh logic decide } else { // Mark existing asset so it won't be deleted asset.refreshStamp = cacheStamp; } } // Remove deleted assets for (int i = AssetList.Count - 1; i >= 0; i--) { if (AssetList[i].refreshStamp != cacheStamp) RemoveAsset(AssetList[i]); } // Only process dirty assets and assets that have never been scanned foreach (var asset in AssetList) // only scan in AssetList { // Skip non-critical assets if (!asset.IsCriticalAsset()) { if (asset.isDirty) { AssetFinderLOG.Log($"[INVALID] non-critical asset is dirty???\n" + $" asset: {asset.assetPath}: isCritical = {asset.IsCriticalAsset()} | isDirty = {asset.isDirty} | assetType: {asset.type}"); } continue; } // Skip ignored assets - they shouldn't have their content read if (asset.IsExcluded) { AssetFinderLOG.Log($"Skipping ignored asset: {asset.assetPath}"); continue; } // Only process if asset is dirty or has never been scanned if (asset.isDirty || !asset.hasBeenScanned) { workCount++; queueLoadContent.Add(asset); } } // Clear the HasChanged flag since we're now processing the changes HasChanged = false; AssetFinderLOG.Log($"Incremental refresh: Processing {workCount} dirty/unscanned assets"); Check4Work(); } internal void Check4Usage() { currentState = ProcessingState.BuildingUsedBy; // CRITICAL FIX: Clear UsedByMap for ALL assets in AssetMap, not just AssetList // This ensures that non-critical assets (like PNGs) get their stale references cleared foreach (var kvp in AssetMap) { var item = kvp.Value; if (item.IsMissing) continue; AssetFinderUnity.Clear(ref item.UsedByMap); } foreach (var item in AssetList) { if (item.IsMissing) continue; AsyncUsedBy(item); } workCount = 0; ready = true; currentState = ProcessingState.Idle; HasChanged = false; // Clear dirty state when processing is complete onReady?.Invoke(); } internal void Check4Work() { if (workCount == 0) { Check4Usage(); return; } ready = false; currentState = ProcessingState.ReadingContent; EditorApplication.update -= AsyncProcess; EditorApplication.update += AsyncProcess; AssetFinderAsset.ClearLog(); } internal void AsyncProcess() { if (this == null) return; if (AssetFinderSettingExt.disable) return; if (EditorApplication.isCompiling || EditorApplication.isUpdating) return; if (frameSkipped++ < 10 - 2 * priority) return; frameSkipped = 0; float t = Time.realtimeSinceStartup; // AssetFinderLOG.Log("AsyncProcess: time=" + Mathf.Round(t) + " : progress = " + progress*workCount + "/" + workCount + " : isReady =" + isReady + " ::: queueLoadCount = " + queueLoadContent.Count); if (!AsyncWork(queueLoadContent, AsyncLoadContent, t)) return; AssetFinderAsset.WriteTotalScanTime(); EditorUtility.SetDirty(this); AssetDatabase.SaveAssets(); EditorApplication.update -= AsyncProcess; if (HasPendingChanges()) { AssetFinderLOG.Log("FR2: Detected changes during processing, restarting incremental refresh"); IncrementalRefresh(); return; } Check4Usage(); } private bool HasPendingChanges() { return AssetMap.Any(kvp => kvp.Value.isDirty && !queueLoadContent.Contains(kvp.Value)); } internal bool AsyncWork(List arr, Action action, float t) { const float FRAME_DURATION = 1f / 60f; // Cache as const to avoid division float endTime = t + FRAME_DURATION; // Calculate end time once int c = arr.Count; while (c-- > 0) { T last = arr[c]; arr.RemoveAt(c); action(c, last); // Check time less frequently to reduce overhead if (Time.realtimeSinceStartup >= endTime) return false; } if (GC_CountDown-- <= 0) // GC every 5 frames { GC.Collect(2, GCCollectionMode.Forced, true, true); GC_CountDown = 5; } return c <= 0; } internal void AsyncLoadContent(int idx, AssetFinderAsset asset) { // Update the current asset name currentAssetName = asset.assetPath; if (asset.fileInfoDirty) asset.LoadFileInfo(); if (asset.fileContentDirty) asset.LoadContentFast(); } internal void AsyncUsedBy(AssetFinderAsset asset) { if (AssetMap == null) Check4Changes(false); if (asset.IsFolder) return; // AssetFinderLOG.Log("Async UsedBy: " + asset.assetPath); foreach (KeyValuePair> item in asset.UseGUIDs) { if (!AssetMap.TryGetValue(item.Key, out AssetFinderAsset tAsset)) continue; if (tAsset == null || tAsset.UsedByMap == null) continue; if (!tAsset.UsedByMap.ContainsKey(asset.guid)) tAsset.AddUsedBy(asset.guid, asset); } } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderCache.AsyncProcessor.cs.meta ================================================ fileFormatVersion: 2 guid: 6b401fe2e5dd2e740bfc479d22492019 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderCache.Constants.cs ================================================ using System.Collections.Generic; namespace VirtueSky.AssetFinder.Editor { internal partial class AssetFinderCache { internal const string DEFAULT_CACHE_PATH = "Assets/_Sunflower/Editor/FinderCache/AssetFinderCache.asset"; internal const string CACHE_VERSION = "2.6.4"; internal static int cacheStamp; internal static System.Action onReady; internal static bool _triedToLoadCache; internal static AssetFinderCache _cache; internal static string _cacheGUID; internal static bool _cacheJustCreated; internal static string _cachePath; public static readonly int priority = 5; private static readonly HashSet SPECIAL_USE_ASSETS = new HashSet { "Assets/link.xml", // this file used to control build/link process do not remove "Assets/csc.rsp", "Assets/mcs.rsp", "Assets/GoogleService-Info.plist", "Assets/google-services.json" }; private static readonly HashSet SPECIAL_EXTENSIONS = new HashSet { ".asmdef", ".cginc", ".cs", ".dll", ".mdb", ".pdb", ".rsp", ".md", ".winmd", ".xml", ".XML", ".tsv", ".csv", ".json", ".pdf", ".txt", ".giparams", ".wlt", ".preset", ".exr", ".aar", ".srcaar", ".pom", ".bin", ".html", ".chm", ".data", ".jsp", ".unitypackage" }; [System.NonSerialized] internal static int delayCounter; } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderCache.Constants.cs.meta ================================================ fileFormatVersion: 2 guid: 6c55ca682f1f6844b8cd730021311b53 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderCache.Lifecycle.cs ================================================ using System; using System.IO; using UnityEditor; using UnityEngine; using System.Linq; namespace VirtueSky.AssetFinder.Editor { internal partial class AssetFinderCache { public static bool CheckSameVersion() { if (_cache == null) return false; return _cache._curCacheVersion == CACHE_VERSION; } public void MarkChanged() { HasChanged = true; } private static void FoundCache() { _cachePath = AssetDatabase.GetAssetPath(_cache); _cache.ReadFromCache(); _cacheGUID = AssetDatabase.AssetPathToGUID(_cachePath); if (AssetFinderSettingExt.isAutoRefreshEnabled || _cacheJustCreated) { if (_cacheJustCreated) _cache.Check4Changes(true); else _cache.RefreshUsedByOnlyFromCache(); } else { _cache.RefreshUsedByOnlyFromCache(); } // Reset flag after use _cacheJustCreated = false; } private static bool RestoreCacheFromPath(string path, bool validateOnly, bool forceLoad) { if (string.IsNullOrEmpty(path)) return false; if (!File.Exists(path)) return false; _cache = AssetFinderUnity.LoadAssetAtPath(path); if (_cache == null) return false; if (validateOnly && !forceLoad) return true; FoundCache(); return true; } private static void TryLoadCache() { _triedToLoadCache = true; // Simple type-based search scoped to Assets/ only var cacheAssets = AssetDatabase.FindAssets("t:AssetFinderCache", new[] { "Assets" }); if (cacheAssets.Length > 0) foreach (var guid in cacheAssets) { var path = AssetDatabase.GUIDToAssetPath(guid); if (!string.IsNullOrEmpty(path) && RestoreCacheFromPath(path, true, true)) return; } } internal static void DeleteCache() { if (_cache == null) return; try { _cache.AssetList.Clear(); _cache.AssetMap.Clear(); _cache.queueLoadContent.Clear(); _cache = null; if (!string.IsNullOrEmpty(_cachePath)) AssetDatabase.DeleteAsset(_cachePath); } catch { // ignored } AssetDatabase.SaveAssets(); using (AssetFinderDev.NoLog) { AssetDatabase.Refresh(); } } internal static void CreateCache() { _cache = CreateInstance(); _cache._curCacheVersion = CACHE_VERSION; var path = Application.dataPath + DEFAULT_CACHE_PATH .Substring(0, DEFAULT_CACHE_PATH.LastIndexOf('/') + 1).Replace("Assets", string.Empty); if (!Directory.Exists(path)) Directory.CreateDirectory(path); AssetDatabase.CreateAsset(_cache, DEFAULT_CACHE_PATH); EditorUtility.SetDirty(_cache); // Set force refresh flag for initial/recreated cache _cacheJustCreated = true; FoundCache(); // Delay the scan by one frame so UI can update first EditorApplication.delayCall -= DelayCheck4Changes; EditorApplication.delayCall += DelayCheck4Changes; } private void OnEnable() { if (_cache == null) _cache = this; } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderCache.Lifecycle.cs.meta ================================================ fileFormatVersion: 2 guid: f5c9fe5f4b20f53498fda1e06bf8ef0a MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderCache.ProjectManager.cs ================================================ using System.Collections.Generic; using UnityEditor; using UnityEngine; namespace VirtueSky.AssetFinder.Editor { internal partial class AssetFinderCache { internal void ReadFromCache() { if (AssetFinderSettingExt.disable) { AssetFinderLOG.LogWarning("Something wrong??? FR2 is disabled!"); } if (AssetList == null) AssetList = new List(); AssetFinderUnity.Clear(ref queueLoadContent); AssetFinderUnity.Clear(ref AssetMap); // Create a new filtered list for critical assets only var filteredAssetList = new List(); for (var i = 0; i < AssetList.Count; i++) { AssetFinderAsset item = AssetList[i]; item.state = AssetFinderAsset.AssetState.CACHE; string path = AssetDatabase.GUIDToAssetPath(item.guid); if (string.IsNullOrEmpty(path)) { item.type = AssetFinderAsset.AssetType.UNKNOWN; // to make sure if GUIDs being reused for a different kind of asset item.state = AssetFinderAsset.AssetState.MISSING; AssetMap.Add(item.guid, item); // Only keep critical assets in AssetList if (item.IsCriticalAsset()) { filteredAssetList.Add(item); } continue; } if (AssetMap.ContainsKey(item.guid)) { AssetFinderLOG.LogWarning("Something wrong, cache found twice <" + item.guid + ">"); continue; } AssetMap.Add(item.guid, item); // Only keep critical assets in AssetList if (item.IsCriticalAsset()) { filteredAssetList.Add(item); } } // Replace AssetList with filtered list containing only critical assets AssetList = filteredAssetList; } internal void ClearCacheCompletely() { // AssetFinderLOG.Log("=== ClearCacheCompletely START ==="); // AssetFinderLOG.Log($"Before Clear - AssetList: {AssetList?.Count ?? 0}, AssetMap: {AssetMap?.Count ?? 0}, queueLoadContent: {queueLoadContent?.Count ?? 0}"); // Clear all cache data structures if (AssetList != null) AssetList.Clear(); else AssetList = new List(); if (AssetMap != null) AssetMap.Clear(); else AssetMap = new Dictionary(); if (queueLoadContent != null) queueLoadContent.Clear(); else queueLoadContent = new List(); // Reset state ready = false; workCount = 0; cacheStamp = 0; HasChanged = false; currentState = ProcessingState.Idle; System.GC.Collect(); } internal void ReadFromProject(bool force) { if (AssetMap == null || AssetMap.Count == 0) ReadFromCache(); foreach (string b in AssetFinderAsset.BUILT_IN_ASSETS) { if (AssetMap.ContainsKey(b)) continue; var asset = new AssetFinderAsset(b); AssetMap.Add(b, asset); // Only add built-in assets to AssetList if they are critical if (asset.IsCriticalAsset()) { AssetList.Add(asset); } } string[] paths = AssetDatabase.GetAllAssetPaths(); cacheStamp++; workCount = 0; if (queueLoadContent != null) queueLoadContent.Clear(); // Check for new assets int validPaths = 0; int newAssets = 0; int existingAssets = 0; foreach (string p in paths) { bool isValid = AssetFinderUnity.StringStartsWith(p, "Assets/", "Packages/", "Library/", "ProjectSettings/"); if (!isValid) { continue; // Skip invalid paths silently to avoid log spam } validPaths++; string guid = AssetDatabase.AssetPathToGUID(p); if (!AssetFinderAsset.IsValidGUID(guid)) { continue; } if (!AssetMap.TryGetValue(guid, out AssetFinderAsset asset)) { newAssets++; AddAsset(guid, force); } else { existingAssets++; asset.refreshStamp = cacheStamp; // mark this asset so it won't be deleted if (!asset.IsCriticalAsset()) continue; // not something we can handle if (!asset.isDirty && !force) continue; if (force) asset.MarkAsDirty(true, true); if (!asset.IsExcluded && (force || _cacheJustCreated || AssetFinderSettingExt.isAutoRefreshEnabled)) { workCount++; queueLoadContent.Add(asset); } } } // Check for deleted assets for (int i = AssetList.Count - 1; i >= 0; i--) { if (AssetList[i].refreshStamp != cacheStamp) RemoveAsset(AssetList[i]); } } internal void RefreshAsset(string guid, bool force) { if (!AssetMap.TryGetValue(guid, out AssetFinderAsset asset)) return; RefreshAsset(asset, force); } internal void RefreshSelection() { string[] list = AssetFinderUnity.Selection_AssetGUIDs; for (var i = 0; i < list.Length; i++) { RefreshAsset(list[i], true); } Check4Work(); } internal void RefreshAsset(AssetFinderAsset asset, bool force) { asset.MarkAsDirty(true, force); // If we're currently processing and this asset isn't already in the queue, add it if (currentState != ProcessingState.Idle && !queueLoadContent.Contains(asset)) { workCount++; queueLoadContent.Add(asset); } DelayCheck4Changes(); } internal void AddAsset(string guid, bool force = false) { if (AssetMap.ContainsKey(guid)) { AssetFinderLOG.LogWarning("guid already exist <" + guid + ">"); return; } var asset = new AssetFinderAsset(guid); asset.LoadPathInfo(); asset.refreshStamp = cacheStamp; AssetMap.Add(guid, asset); // Do not load content for AssetFinderCache asset if (guid == CacheGUID) return; if (!asset.IsCriticalAsset()) return; // Critical assets (even if ignored) should be added to AssetList AssetList.Add(asset); // CRITICAL FIX: Always queue new assets for content loading when force=true bool shouldQueue = !asset.IsExcluded && (force || _cacheJustCreated || AssetFinderSettingExt.isAutoRefreshEnabled || currentState != ProcessingState.Idle); // AssetFinderLOG.Log($"AddAsset: {asset.assetPath} - shouldQueue: {shouldQueue} (IsExcluded: {asset.IsExcluded}, force: {force}, _cacheJustCreated: {_cacheJustCreated}, autoRefresh: {AssetFinderSettingExt.isAutoRefreshEnabled}, currentState: {currentState})"); if (shouldQueue) { workCount++; queueLoadContent.Add(asset); // AssetFinderLOG.Log($"QUEUED new asset for content loading: {asset.assetPath}"); } else { // When content loading is skipped, mark as ready but dirty for future scans asset.MarkAsDirty(true, false); // AssetFinderLOG.Log($"SKIPPED new asset: {asset.assetPath} - marked as dirty for future scan"); } } internal void RemoveAsset(string guid) { if (!AssetMap.ContainsKey(guid)) return; RemoveAsset(AssetMap[guid]); } internal void RemoveAsset(AssetFinderAsset asset) { AssetList.Remove(asset); // Deleted Asset : still in the map but not in the AssetList asset.state = AssetFinderAsset.AssetState.MISSING; } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderCache.ProjectManager.cs.meta ================================================ fileFormatVersion: 2 guid: 462f88bf52231f446ad48db4501584fa MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderCache.Scanner.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using UnityEditor; namespace VirtueSky.AssetFinder.Editor { internal partial class AssetFinderCache { internal List> ScanSimilar(Action IgnoreWhenScan, Action IgnoreFolderWhenScan) { if (AssetMap == null) Check4Changes(true); var dict = new Dictionary>(); foreach (KeyValuePair item in AssetMap) { if (item.Value == null) continue; if (item.Value.IsMissing || item.Value.IsFolder) continue; if (item.Value.inPlugins) continue; if (item.Value.inEditor) continue; if (item.Value.IsExcluded) continue; if (!item.Value.assetPath.StartsWith("Assets/")) continue; if (AssetFinderSetting.IsTypeExcluded(AssetFinderAssetGroupDrawer.GetIndex(item.Value.extension))) { if (IgnoreWhenScan != null) IgnoreWhenScan(); continue; } string hash = item.Value.fileInfoHash; if (string.IsNullOrEmpty(hash)) { AssetFinderLOG.LogWarning("Hash can not be null! "); continue; } if (!dict.TryGetValue(hash, out List list)) { list = new List(); dict.Add(hash, list); } list.Add(item.Value); } return dict.Values .Where(item => item.Count > 1) .OrderByDescending(item => item[0].fileSize) .Select(item => item.Select(asset => asset.assetPath).ToList()) .ToList(); } internal List ScanUnused(bool recursive = true) { if (AssetMap == null) Check4Changes(false); // Get Addressable assets HashSet addressable = AssetFinderAddressable.isOk ? AssetFinderAddressable.GetAddresses() .SelectMany(item => item.Value.assetGUIDs.Union(item.Value.childGUIDs)) .ToHashSet() : new HashSet(); var result = new List(); var unusedAssets = new HashSet(); // First pass: find directly unused assets (level 1) foreach (KeyValuePair item in AssetMap) { AssetFinderAsset v = item.Value; if (v.IsMissing || v.inEditor || v.IsScript || v.inResources || v.inPlugins || v.inStreamingAsset || v.IsFolder) continue; if (!v.assetPath.StartsWith("Assets/")) continue; // ignore built-in / packages assets if (v.forcedIncludedInBuild) continue; // ignore assets that are forced to be included in build if (v.assetName == "LICENSE") continue; // ignore license files // --- Ignore assets in ignored folders or exact ignored paths --- bool isIgnored = AssetFinderSetting.IgnoreAsset.Any(ignore => v.assetPath.Equals(ignore, StringComparison.OrdinalIgnoreCase) || (v.assetPath.StartsWith(ignore + "/", StringComparison.OrdinalIgnoreCase)) ); if (isIgnored) continue; // --- Ignore assets with unknown or no extension --- string ext = System.IO.Path.GetExtension(v.assetPath); Type assetType = UnityEditor.AssetDatabase.GetMainAssetTypeAtPath(v.assetPath); if (string.IsNullOrEmpty(ext) || assetType == typeof(DefaultAsset)) { continue; } if (SPECIAL_USE_ASSETS.Contains(v.assetPath)) continue; // ignore assets with special use (can not remove) if (SPECIAL_EXTENSIONS.Contains(v.extension)) continue; if (v.type == AssetFinderAsset.AssetType.DLL) continue; if (v.type == AssetFinderAsset.AssetType.SCRIPT) continue; if (v.type == AssetFinderAsset.AssetType.UNKNOWN) continue; if (addressable.Contains(v.guid)) continue; // special handler for .spriteatlas if (v.extension == ".spriteatlas") { var isInUsed = false; List allSprites = v.UseGUIDs.Keys.ToList(); foreach (string spriteGUID in allSprites) { AssetFinderAsset asset = Api.Get(spriteGUID); if (asset.UsedByMap.Count <= 1) continue; // only use by this atlas isInUsed = true; break; // this one is used by other assets } if (isInUsed) continue; } if (v.IsExcluded) { // Debug.Log($"Excluded: {v.assetPath}"); continue; } if (!string.IsNullOrEmpty(v.AtlasName)) continue; if (!string.IsNullOrEmpty(v.AssetBundleName)) continue; if (!string.IsNullOrEmpty(v.AddressableName)) continue; if (v.UsedByMap.Count == 0) //&& !AssetFinderAsset.IGNORE_UNUSED_GUIDS.Contains(v.guid) { result.Add(v); unusedAssets.Add(v.guid); } } // If not recursive, return the level 1 results if (!recursive) { result.Sort((item1, item2) => item1.extension == item2.extension ? string.Compare(item1.assetPath, item2.assetPath, StringComparison.Ordinal) : string.Compare(item1.extension, item2.extension, StringComparison.Ordinal)); return result; } // Recursive scan for higher level unused assets bool foundNewUnused = true; while (foundNewUnused) { foundNewUnused = false; var newUnusedAssets = new HashSet(); foreach (KeyValuePair item in AssetMap) { AssetFinderAsset v = item.Value; // Skip if already in result or doesn't meet basic criteria if (unusedAssets.Contains(v.guid)) continue; if (v.IsMissing || v.inEditor || v.IsScript || v.inResources || v.inPlugins || v.inStreamingAsset || v.IsFolder) continue; if (!v.assetPath.StartsWith("Assets/")) continue; if (v.forcedIncludedInBuild) continue; if (v.assetName == "LICENSE") continue; // --- Ignore assets in ignored folders or exact ignored paths --- bool isIgnored = AssetFinderSetting.IgnoreAsset.Any(ignore => v.assetPath.Equals(ignore, StringComparison.OrdinalIgnoreCase) || (v.assetPath.StartsWith(ignore + "/", StringComparison.OrdinalIgnoreCase)) ); if (isIgnored) continue; // --- Ignore assets with unknown or no extension --- string ext = System.IO.Path.GetExtension(v.assetPath); Type assetType = UnityEditor.AssetDatabase.GetMainAssetTypeAtPath(v.assetPath); if (string.IsNullOrEmpty(ext) || assetType == typeof(DefaultAsset)) { continue; } if (SPECIAL_USE_ASSETS.Contains(v.assetPath)) continue; if (SPECIAL_EXTENSIONS.Contains(v.extension)) continue; if (v.type == AssetFinderAsset.AssetType.DLL) continue; if (v.type == AssetFinderAsset.AssetType.SCRIPT) continue; if (v.type == AssetFinderAsset.AssetType.UNKNOWN) continue; if (addressable.Contains(v.guid)) continue; if (v.IsExcluded) continue; if (!string.IsNullOrEmpty(v.AtlasName)) continue; if (!string.IsNullOrEmpty(v.AssetBundleName)) continue; if (!string.IsNullOrEmpty(v.AddressableName)) continue; // Check if this asset is only used by already identified unused assets if (v.UsedByMap.Count > 0) { bool onlyUsedByUnusedAssets = true; foreach (var usedBy in v.UsedByMap) { if (!unusedAssets.Contains(usedBy.Key)) { onlyUsedByUnusedAssets = false; break; } } if (onlyUsedByUnusedAssets) { result.Add(v); newUnusedAssets.Add(v.guid); foundNewUnused = true; } } } // Add newly found unused assets to the master list unusedAssets.UnionWith(newUnusedAssets); } result.Sort((item1, item2) => item1.extension == item2.extension ? string.Compare(item1.assetPath, item2.assetPath, StringComparison.Ordinal) : string.Compare(item1.extension, item2.extension, StringComparison.Ordinal)); return result; } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderCache.Scanner.cs.meta ================================================ fileFormatVersion: 2 guid: 294f715733c2fbf41b655b25454bf807 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderCache.Search.cs ================================================ using System.Collections.Generic; using System.Linq; using UnityEngine; namespace VirtueSky.AssetFinder.Editor { internal partial class AssetFinderCache { internal static List FindUsage(string[] listGUIDs) { if (!isReady) return null; List refs = Api.FindAssets(listGUIDs, true); for (var i = 0; i < refs.Count; i++) { List tmp = AssetFinderAsset.FindUsage(refs[i]); for (var j = 0; j < tmp.Count; j++) { AssetFinderAsset itm = tmp[j]; if (refs.Contains(itm)) continue; refs.Add(itm); } } return refs.Select(item => item.guid).ToList(); } internal AssetFinderAsset Get(string guid, bool autoNew = false) { if (autoNew && !AssetMap.ContainsKey(guid)) AddAsset(guid); return AssetMap.GetValueOrDefault(guid); } internal List FindAssetsOfType(AssetFinderAsset.AssetType type) { var result = new List(); foreach (KeyValuePair item in AssetMap) { if (item.Value.type != type) continue; result.Add(item.Value); } return result; } internal AssetFinderAsset FindAsset(string guid, string fileId) { if (AssetMap == null) Check4Changes(false); if (!isReady) { AssetFinderLOG.LogWarning("Cache not ready !"); return null; } if (string.IsNullOrEmpty(guid)) return null; //for (var i = 0; i < guids.Length; i++) { //string guid = guids[i]; if (!AssetMap.TryGetValue(guid, out AssetFinderAsset asset)) return null; if (asset.IsMissing) return null; if (asset.IsFolder) return null; return asset; } } internal List FindAssets(string[] guids, bool scanFolder) { if (AssetMap == null) Check4Changes(false); var result = new List(); if (!isReady) { AssetFinderLOG.LogWarning("Cache not ready !"); return result; } var folderList = new List(); if (guids.Length == 0) return result; for (var i = 0; i < guids.Length; i++) { string guid = guids[i]; AssetFinderAsset asset; if (!AssetMap.TryGetValue(guid, out asset)) continue; if (asset.IsMissing) continue; if (asset.IsFolder) { if (!folderList.Contains(asset)) folderList.Add(asset); } else { result.Add(asset); } } if (!scanFolder || folderList.Count == 0) return result; int count = folderList.Count; for (var i = 0; i < count; i++) { AssetFinderAsset item = folderList[i]; // for (var j = 0; j < item.UseGUIDs.Count; j++) // { // AssetFinderAsset a; // if (!AssetMap.TryGetValue(item.UseGUIDs[j], out a)) continue; foreach (KeyValuePair> useM in item.UseGUIDs) { AssetFinderAsset a; if (!AssetMap.TryGetValue(useM.Key, out a)) continue; if (a.IsMissing) continue; if (a.IsFolder) { if (!folderList.Contains(a)) { folderList.Add(a); count++; } } else { result.Add(a); } } } return result; } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderCache.Search.cs.meta ================================================ fileFormatVersion: 2 guid: 96e6f3d54f320f74cbcb5ebb0e8f987e MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderCache.cs ================================================ //#define AssetFinderDEBUG using System; using System.Collections.Generic; using System.IO; using System.Linq; using UnityEditor; using UnityEngine; using UnityObject = UnityEngine.Object; namespace VirtueSky.AssetFinder.Editor { internal partial class AssetFinderCache : ScriptableObject { [SerializeField] private bool _autoRefresh; [SerializeField] private string _curCacheVersion; [SerializeField] public List AssetList; [SerializeField] internal AssetFinderSetting setting = new AssetFinderSetting(); // ----------------------------------- INSTANCE ------------------------------------- [SerializeField] public int timeStamp; [NonSerialized] internal Dictionary AssetMap; // Track the current asset being processed [NonSerialized] internal string currentAssetName; private int frameSkipped; internal int GC_CountDown = 5; [NonSerialized] internal List queueLoadContent; internal bool ready; [NonSerialized] internal int workCount; [NonSerialized] internal ProcessingState currentState = ProcessingState.Idle; internal static string CacheGUID { get { if (!string.IsNullOrEmpty(_cacheGUID)) return _cacheGUID; if (_cache != null) { _cachePath = AssetDatabase.GetAssetPath(_cache); _cacheGUID = AssetDatabase.AssetPathToGUID(_cachePath); return _cacheGUID; } return null; } } internal static string CachePath { get { if (!string.IsNullOrEmpty(_cachePath)) return _cachePath; if (_cache != null) { _cachePath = AssetDatabase.GetAssetPath(_cache); return _cachePath; } return null; } } [SerializeField] private bool _hasChanged; public bool HasChanged { get => _hasChanged; private set => _hasChanged = value; } internal static bool hasChanges => Api != null && Api.workCount > 0; public static void Reload() { DelayCheck4Changes(); } internal static AssetFinderCache Api { get { if (_cache != null) return _cache; if (!_triedToLoadCache) TryLoadCache(); return _cache; } } internal static bool isReady { get { if (AssetFinderSettingExt.disable) return false; if (!_triedToLoadCache) TryLoadCache(); return (_cache != null) && _cache.ready; } } internal static bool hasCache { get { if (!_triedToLoadCache) TryLoadCache(); return _cache != null; } } internal float progress { get { int n = workCount - queueLoadContent.Count; return workCount == 0 ? 1 : n / (float)workCount; } } } internal enum ProcessingState { Idle, // Not processing anything ReadingContent, // Currently reading asset content BuildingUsedBy // Currently building usedBy relationships } internal static class AssetFinderLOG { public static void Log(object message) { #if AssetFinderDEBUG || AssetFinderDEV UnityEngine.Debug.Log(message); #endif } public static void Log(object message, UnityEngine.Object context) { #if AssetFinderDEBUG || AssetFinderDEV UnityEngine.Debug.Log(message, context); #endif } public static void LogWarning(object message) { #if AssetFinderDEBUG || AssetFinderDEV UnityEngine.Debug.LogWarning(message); #endif } public static void LogWarning(object message, UnityEngine.Object context) { #if AssetFinderDEBUG || AssetFinderDEV UnityEngine.Debug.LogWarning(message, context); #endif } public static void LogError(object message) { #if AssetFinderDEBUG || AssetFinderDEV UnityEngine.Debug.LogError(message); #endif } public static void LogError(object message, UnityEngine.Object context) { #if AssetFinderDEBUG || AssetFinderDEV UnityEngine.Debug.LogError(message, context); #endif } } [CustomEditor(typeof(AssetFinderCache))] internal class AssetFinderCacheEditor : UnityEditor.Editor { private static string inspectGUID; private static int index; public override void OnInspectorGUI() { var c = (AssetFinderCache)target; GUILayout.Label("Total : " + c.AssetList.Count); // AssetFinderCache.DrawPriorityGUI(); UnityObject s = Selection.activeObject; if (s == null) return; string guid = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(s)); if (inspectGUID != guid) { inspectGUID = guid; index = c.AssetList.FindIndex(item => item.guid == guid); } if (index != -1) { if (index >= c.AssetList.Count) index = 0; serializedObject.Update(); SerializedProperty prop = serializedObject.FindProperty("AssetList").GetArrayElementAtIndex(index); prop.isExpanded = true; EditorGUILayout.PropertyField(prop, true); } } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderCache.cs.meta ================================================ fileFormatVersion: 2 guid: 30361f5a1e2f6bf449882a4a0fb04e00 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderGitUtil.cs ================================================ using System.IO; using UnityEngine; namespace VirtueSky.AssetFinder.Editor { internal static class AssetFinderGitUtil { private static string gitRootPath; public static bool IsGitProject() { if (!string.IsNullOrEmpty(gitRootPath)) return true; string currentPath = Application.dataPath; DirectoryInfo dir = new DirectoryInfo(currentPath); var maxDepth = 10; while (dir != null && maxDepth > 0) // Prevent infinite loop { maxDepth--; if (Directory.Exists(Path.Combine(dir.FullName, ".git"))) { gitRootPath = dir.FullName; return true; } dir = dir.Parent; } return false; } public static bool CheckGitIgnoreContainsFR2Cache() { if (string.IsNullOrEmpty(gitRootPath)) IsGitProject(); if (string.IsNullOrEmpty(gitRootPath)) return false; string gitIgnorePath = Path.Combine(gitRootPath, ".gitignore"); if (!File.Exists(gitIgnorePath)) return false; string[] lines = File.ReadAllLines(gitIgnorePath); foreach (string line in lines) { string trimmedLine = line.Trim(); if (string.IsNullOrEmpty(trimmedLine) || trimmedLine.StartsWith("#")) continue; if (trimmedLine == "**/AssetFinderCache.asset*" || trimmedLine == "AssetFinderCache.asset*" || trimmedLine == "*AssetFinderCache.asset*") { return true; } } return false; } public static void AddFR2CacheToGitIgnore() { try { string content = File.Exists(".gitignore") ? File.ReadAllText(".gitignore") : ""; // Make sure the file ends with a newline if (!string.IsNullOrEmpty(content) && !content.EndsWith("\n")) { content += "\n"; } content += "**/AssetFinderCache.asset*\n"; File.WriteAllText(".gitignore", content); } catch (System.Exception e) { AssetFinderLOG.LogError($"Failed to update .gitignore: {e.Message}"); } } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderGitUtil.cs.meta ================================================ fileFormatVersion: 2 guid: fdb05d77241c6fe4093af96a6787ef3a MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderNavigationHistory.cs ================================================ using System.Collections.Generic; using System.Linq; using UnityEditor; using UnityEngine; using UnityObject = UnityEngine.Object; namespace VirtueSky.AssetFinder.Editor { internal class AssetFinderNavigationHistory { private readonly List history = new List(); private int currentIndex = -1; private const int MAX_HISTORY_SIZE = 20; private AssetFinderWindowAll window; private bool isNavigating = false; public bool CanGoBack => currentIndex > 0 && GetValidHistoryCount() > 1; public bool CanGoForward => currentIndex < history.Count - 1 && GetValidHistoryCount() > 1; public void SetWindow(AssetFinderWindowAll windowAll) { window = windowAll; } public void RecordSelection(UnityObject[] selection) { if (selection == null || selection.Length == 0) return; if (isNavigating) return; var validSelection = selection.Where(obj => obj != null).ToArray(); if (validSelection.Length == 0) return; if (currentIndex >= 0 && currentIndex < history.Count) { UnityObject[] current = CleanHistoryEntry(history[currentIndex]); if (AreSelectionsEqual(current, validSelection)) return; } if (currentIndex < history.Count - 1) { history.RemoveRange(currentIndex + 1, history.Count - currentIndex - 1); } history.Add(validSelection.ToArray()); currentIndex = history.Count - 1; if (history.Count > MAX_HISTORY_SIZE) { history.RemoveAt(0); currentIndex--; } } public bool GoBack() { if (!CanGoBack) return false; CleanInvalidHistoryEntries(); if (currentIndex <= 0) return false; currentIndex--; var validSelection = CleanHistoryEntry(history[currentIndex]); if (validSelection.Length == 0) { history.RemoveAt(currentIndex); if (currentIndex >= history.Count) currentIndex = history.Count - 1; return GoBack(); } isNavigating = true; UpdateFR2SelectionDirectly(validSelection); isNavigating = false; return true; } public bool GoForward() { if (!CanGoForward) return false; CleanInvalidHistoryEntries(); if (currentIndex >= history.Count - 1) return false; currentIndex++; var validSelection = CleanHistoryEntry(history[currentIndex]); if (validSelection.Length == 0) { history.RemoveAt(currentIndex); currentIndex--; return GoForward(); } isNavigating = true; UpdateFR2SelectionDirectly(validSelection); isNavigating = false; return true; } private void CleanInvalidHistoryEntries() { for (int i = history.Count - 1; i >= 0; i--) { var cleanedEntry = CleanHistoryEntry(history[i]); if (cleanedEntry.Length == 0) { history.RemoveAt(i); if (currentIndex >= i) currentIndex--; } else { history[i] = cleanedEntry; } } if (currentIndex < 0 && history.Count > 0) currentIndex = 0; if (currentIndex >= history.Count) currentIndex = history.Count - 1; } private UnityObject[] CleanHistoryEntry(UnityObject[] entry) { return entry?.Where(obj => obj != null).ToArray() ?? new UnityObject[0]; } private int GetValidHistoryCount() { return history.Count(entry => CleanHistoryEntry(entry).Length > 0); } private void UpdateFR2SelectionDirectly(UnityObject[] selection) { if (window == null) return; var validSelection = selection?.Where(obj => obj != null).ToArray() ?? new UnityObject[0]; // For navigation history, we want to directly set both Unity and FR2 selection // We bypass the smart lock mechanism entirely by setting FR2 selection directly window.SetFR2Selection(validSelection); Selection.objects = validSelection; } private static bool AreSelectionsEqual(UnityObject[] a, UnityObject[] b) { if (a.Length != b.Length) return false; for (int i = 0; i < a.Length; i++) { if (a[i] != b[i]) return false; } return true; } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderNavigationHistory.cs.meta ================================================ fileFormatVersion: 2 guid: ac0493b90c0af8f4fb734aa7650864ac MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderSelectionManager.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using UnityEditor; using UnityEngine; using UnityObject = UnityEngine.Object; namespace VirtueSky.AssetFinder.Editor { /// /// Unified Selection Manager for FindReference2 /// /// This system replaces the fragmented selection logic found in multiple classes and provides: /// /// BENEFITS: /// - Single source of truth for all selection state /// - Automatic Unity version compatibility (2019.4+ vs 2021+) /// - Separation of scene objects vs assets with proper typing /// - Reduced GC pressure through efficient data structures /// - Centralized Selection.selectionChanged monitoring /// - Thread-safe singleton pattern /// /// ARCHITECTURE: /// - AssetFinderSelectionManager: Main coordinator and event dispatcher /// - AssetFinderSceneSelection: Handles GameObject/Component selection with int instanceIds /// - AssetFinderAssetSelection: Handles asset selection with GUID/FileID pairs /// /// UNITY VERSION DIFFERENCES HANDLED: /// - Unity 2018.1+: Uses AssetDatabase.TryGetGUIDAndLocalFileIdentifier /// - Pre-2018.1: Uses reflection to access m_LocalIdentfierInFile property /// /// USAGE: /// - Window classes subscribe to AssetFinderSelectionManager.SelectionChanged /// - Access current selection via Instance.SceneSelection or Instance.AssetSelection /// - All selection changes automatically propagate to subscribers /// /// MIGRATION: /// - Replaces scattered Selection.objects calls /// - Eliminates string-based instanceId storage /// - Removes duplicated Unity version compatibility code /// - Centralizes selection caching and frame-based optimization /// [InitializeOnLoad] internal class AssetFinderSelectionManager { public static event System.Action SelectionChanged; private static AssetFinderSelectionManager _instance; // Static constructor - called automatically when Unity loads/recompiles static AssetFinderSelectionManager() { // Initialize immediately when class is loaded Initialize(); } public static AssetFinderSelectionManager Instance { get { if (_instance != null) return _instance; Initialize(); return _instance; } } private AssetFinderSceneSelection sceneSelection; private AssetFinderAssetSelection assetSelection; // Cached Unity selection for comparison private UnityObject[] cachedUnitySelection = Array.Empty(); public AssetFinderSceneSelection SceneSelection => sceneSelection; public AssetFinderAssetSelection AssetSelection => assetSelection; public bool IsSelectingSceneObjects => sceneSelection?.Count > 0; public bool IsSelectingAssets => assetSelection?.Count > 0; public bool HasSelection => TotalCount > 0; public int TotalCount => (sceneSelection?.Count ?? 0) + (assetSelection?.Count ?? 0); private static void Initialize() { if (_instance != null) { Debug.LogWarning("AssetFinderSelectionManager already initialized - cleaning up first"); Cleanup(); } _instance = new AssetFinderSelectionManager(); _instance.InitializeInstance(); // Ensure cleanup happens on domain reload #if UNITY_2019_1_OR_NEWER UnityEditor.AssemblyReloadEvents.beforeAssemblyReload -= Cleanup; UnityEditor.AssemblyReloadEvents.beforeAssemblyReload += Cleanup; #endif } private void InitializeInstance() { sceneSelection = new AssetFinderSceneSelection(); assetSelection = new AssetFinderAssetSelection(); // Ensure we don't double-subscribe (idempotent) Selection.selectionChanged -= OnUnitySelectionChanged; Selection.selectionChanged += OnUnitySelectionChanged; // Initialize with current Unity selection RefreshFromUnitySelection(); } public UnityObject[] GetUnitySelection() { return cachedUnitySelection ?? Array.Empty(); } private void RefreshFromUnitySelection() { var currentSelection = Selection.objects ?? Array.Empty(); if (AreSelectionsEqual(cachedUnitySelection, currentSelection)) return; cachedUnitySelection = currentSelection; UpdateFR2Selection(currentSelection); SelectionChanged?.Invoke(); } private static bool AreSelectionsEqual(UnityObject[] selection1, UnityObject[] selection2) { if (selection1 == null && selection2 == null) return true; if (selection1 == null || selection2 == null) return false; if (selection1.Length != selection2.Length) return false; // Order matters for selection comparison for (int i = 0; i < selection1.Length; i++) { if (selection1[i] != selection2[i]) return false; } return true; } internal void UpdateFR2Selection(UnityObject[] newSelection) { sceneSelection.Clear(); assetSelection.Clear(); if (newSelection == null || newSelection.Length == 0) return; foreach (var obj in newSelection) { if (obj == null) continue; if (AssetDatabase.Contains(obj)) { assetSelection.AddAsset(obj); } else if (obj is GameObject gameObject) { sceneSelection.AddGameObject(gameObject); } else if (obj is Component component && component.gameObject != null) { sceneSelection.AddGameObject(component.gameObject); } } } private void OnUnitySelectionChanged() { // AssetFinderLOG.Log("OnUnitySelectionChanged()"); RefreshFromUnitySelection(); } public static void Cleanup() { if (_instance == null) return; Selection.selectionChanged -= _instance.OnUnitySelectionChanged; _instance = null; } internal class AssetFinderSceneSelection { private readonly HashSet instanceIds = new HashSet(); private readonly Dictionary gameObjects = new Dictionary(); // Cached array - updated only when collection changes private GameObject[] cachedGameObjectArray = Array.Empty(); private bool arrayDirty = false; public int Count => instanceIds.Count; public IReadOnlyCollection InstanceIds => instanceIds; public IReadOnlyCollection GameObjects => gameObjects.Values; public void AddGameObject(UnityObject obj) { if (obj == null) return; GameObject go = obj as GameObject ?? (obj as Component)?.gameObject; if (go == null) return; int instanceId = go.GetInstanceID(); if (instanceIds.Add(instanceId)) { gameObjects[instanceId] = go; arrayDirty = true; } } public void Remove(int instanceId) { if (instanceIds.Remove(instanceId)) { gameObjects.Remove(instanceId); arrayDirty = true; } } public bool Contains(int instanceId) { return instanceIds.Contains(instanceId); } public bool Contains(GameObject go) { return go != null && instanceIds.Contains(go.GetInstanceID()); } public void Clear() { instanceIds.Clear(); gameObjects.Clear(); arrayDirty = true; } public GameObject[] ToArray() { if (arrayDirty) { cachedGameObjectArray = gameObjects.Values.Where(go => go != null).ToArray(); arrayDirty = false; } return cachedGameObjectArray; } } internal class AssetFinderAssetSelection { private readonly Dictionary assets = new Dictionary(); // Cached arrays - updated only when collection changes private string[] cachedGuidsArray = Array.Empty(); private bool guidArrayDirty = false; public int Count => assets.Count; public IReadOnlyCollection AssetGuids => assets.Keys; public IReadOnlyCollection AssetEntries => assets.Values; public struct AssetEntry { public string guid; public long fileId; public string assetPath; public AssetEntry(string guid, long fileId, string assetPath) { this.guid = guid; this.fileId = fileId; this.assetPath = assetPath; } } public void AddAsset(UnityObject obj) { if (obj == null) return; string assetPath = AssetDatabase.GetAssetPath(obj); if (string.IsNullOrEmpty(assetPath)) return; string guid = AssetDatabase.AssetPathToGUID(assetPath); if (string.IsNullOrEmpty(guid)) return; long fileId = GetFileId(obj); if (!assets.ContainsKey(guid)) { guidArrayDirty = true; } assets[guid] = new AssetEntry(guid, fileId, assetPath); } private static long GetFileId(UnityObject obj) { #if UNITY_2018_1_OR_NEWER if (AssetDatabase.TryGetGUIDAndLocalFileIdentifier(obj, out _, out long fileId)) { return fileId; } #else try { var serializedObject = new SerializedObject(obj); var inspectorModeInfo = typeof(SerializedObject).GetProperty("inspectorMode", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); inspectorModeInfo?.SetValue(serializedObject, InspectorMode.Debug, null); var localIdProp = serializedObject.FindProperty("m_LocalIdentfierInFile"); if (localIdProp != null) { long localId = localIdProp.longValue; if (localId <= 0) localId = localIdProp.intValue; return localId; } } catch { } #endif return -1; } public void Remove(string guid) { if (assets.Remove(guid)) { guidArrayDirty = true; } } public bool Contains(string guid) { return assets.ContainsKey(guid); } public void Clear() { assets.Clear(); guidArrayDirty = true; } public string[] GetGuids() { if (guidArrayDirty) { cachedGuidsArray = assets.Keys.ToArray(); guidArrayDirty = false; } return cachedGuidsArray; } public AssetEntry? GetAssetEntry(string guid) { if (assets.TryGetValue(guid, out var entry)) return entry; return null; } } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderSelectionManager.cs.meta ================================================ fileFormatVersion: 2 guid: 21a87406f1e91644592297a6bf1e285d MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderSettingExt.cs ================================================ using System; using System.IO; using UnityEditor; using UnityEngine; namespace VirtueSky.AssetFinder.Editor { [Serializable] internal class AssetFinderSettingExt { public static AssetFinderAutoRefreshMode autoRefreshMode { get => inst._autoRefresh; set { if (inst._autoRefresh == value) return; inst._autoRefresh = value; EditorUtility.SetDirty(AssetFinderCache.Api); EditorApplication.update -= DelaySave; EditorApplication.update += DelaySave; } } public static bool isAutoRefreshEnabled { get { if (EditorApplication.isPlayingOrWillChangePlaymode) return false; return autoRefreshMode == AssetFinderAutoRefreshMode.On; } } public static bool disable { get => inst.internalDisabled; set => inst.internalDisabled = value; } public static bool hideToolsWarning { get => inst._hideToolsWarning; set { if (inst._hideToolsWarning == value) return; inst._hideToolsWarning = value; EditorUtility.SetDirty(AssetFinderCache.Api); EditorApplication.update -= DelaySave; EditorApplication.update += DelaySave; } } public static bool isGitProject; public static bool gitIgnoreAdded { get => inst._gitIgnoreAdded; set { if (inst._gitIgnoreAdded == value) return; inst._gitIgnoreAdded = value; EditorUtility.SetDirty(AssetFinderCache.Api); EditorApplication.update -= DelaySave; EditorApplication.update += DelaySave; } } public static bool hideGitIgnoreWarning { get => inst._hideGitIgnoreWarning; set { if (inst._hideGitIgnoreWarning == value) return; inst._hideGitIgnoreWarning = value; EditorUtility.SetDirty(AssetFinderCache.Api); EditorApplication.update -= DelaySave; EditorApplication.update += DelaySave; } } private const string path = "Library/FR2/fr2.cfg"; private static AssetFinderSettingExt inst; static AssetFinderSettingExt() { inst = new AssetFinderSettingExt(); if (!File.Exists(path)) return; try { string content = File.ReadAllText(path); JsonUtility.FromJsonOverwrite(content, inst); } catch (Exception e) { AssetFinderLOG.LogWarning(e); } } static void DelaySave() { EditorApplication.update -= DelaySave; try { Directory.CreateDirectory("Library/FR2/"); File.WriteAllText(path, JsonUtility.ToJson(inst)); } catch (Exception e) { AssetFinderLOG.LogWarning(e); } } [SerializeField] private bool _disableInPlayMode = true; [SerializeField] private bool _disabled; [SerializeField] private AssetFinderAutoRefreshMode _autoRefresh; [SerializeField] private bool _hideToolsWarning; [SerializeField] private bool _isGitProject; [SerializeField] private bool _gitIgnoreAdded; [SerializeField] private bool _hideGitIgnoreWarning; private bool internalDisabled { get => _disabled || (_disableInPlayMode && EditorApplication.isPlayingOrWillChangePlaymode); set { ref bool disableRef = ref _disabled; if (EditorApplication.isPlayingOrWillChangePlaymode) disableRef = ref _disableInPlayMode; if (disableRef == value) return; disableRef = value; // disable at runtime: only disable `disableInPlayMode` // enable at runtime: enable all if (!value) _disabled = false; EditorUtility.SetDirty(AssetFinderCache.Api); EditorApplication.update -= DelaySave; EditorApplication.update += DelaySave; } } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderSettingExt.cs.meta ================================================ fileFormatVersion: 2 guid: 42a3a6faf827daa46aa8f448c8aec943 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderSmartLock.cs ================================================ // #define AssetFinderDEBUG using System; using UnityEditor; using UnityEngine; using UnityObject = UnityEngine.Object; namespace VirtueSky.AssetFinder.Editor { internal class AssetFinderSmartLock { public enum PingLockState { None, Scene, // Ping/highlight action triggered from scene context Asset // Ping/highlight action triggered from asset context } private PingLockState pingLockState = PingLockState.None; public void SetPingLockState(PingLockState state) { pingLockState = state; #if AssetFinderDEBUG if (state != PingLockState.None) { AssetFinderLOG.Log($"SmartLock: Set ping lock state to {state}"); } #endif } public bool ConsumePingLockState() { bool hadPingLock = pingLockState != PingLockState.None; if (hadPingLock) { // AssetFinderLOG.Log($"SmartLock: Consuming ping lock state {pingLockState}"); pingLockState = PingLockState.None; } return hadPingLock; } public bool ShouldRefreshWithSmartLogic(EditorWindow window, UnityObject[] panelSelection = null) { if (!AssetFinderSelectionManager.Instance.HasSelection) return false; if (ConsumePingLockState()) return false; if (panelSelection == null || panelSelection.Length == 0) return true; return window != EditorWindow.focusedWindow; } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderSmartLock.cs.meta ================================================ fileFormatVersion: 2 guid: b83b815529ea4e343857b73a07eb868b MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderWindowFocus.cs ================================================ using System; using UnityEditor; using UnityEditor.Compilation; namespace VirtueSky.AssetFinder.Editor { [InitializeOnLoad] public static class AssetFinderWindowFocus { public static event Action FocusedWindowChanged = delegate { }; public static string CurrentWindowType => EditorWindow.focusedWindow?.GetType().Name; public static string PreviousWindowType { get; private set; } #if UNITY_6000_0_OR_NEWER // ---------- Native implementation ---------- static AssetFinderWindowFocus() { EditorWindow.windowFocusChanged += Raise; AssemblyReloadEvents.beforeAssemblyReload += Cleanup; } private static void Raise() { var current = EditorWindow.focusedWindow; PreviousWindowType = _lastWindowType; _lastWindowType = current?.GetType().Name; if (current != null) FocusedWindowChanged(current); } private static void Cleanup() => EditorWindow.windowFocusChanged -= Raise; #elif UNITY_2023_1_OR_NEWER // ---------- Legacy implementation for Unity 2023-2024 ---------- static AssetFinderWindowFocus() { EditorWindow.focusedWindowChanged += Raise; AssemblyReloadEvents.beforeAssemblyReload += Cleanup; } private static void Raise() { var current = EditorWindow.focusedWindow; PreviousWindowType = _lastWindowType; _lastWindowType = current?.GetType().Name; if (current != null) FocusedWindowChanged(current); } private static void Cleanup() => EditorWindow.focusedWindowChanged -= Raise; #else // ---------- Fallback: poll each editor-tick ---------- private static EditorWindow _last; static AssetFinderWindowFocus() { EditorApplication.update += Tick; AssemblyReloadEvents.beforeAssemblyReload += Cleanup; } private static void Tick() { var current = EditorWindow.focusedWindow; if (current == _last) return; PreviousWindowType = _lastWindowType; _last = current; _lastWindowType = current?.GetType().Name; if (current != null) FocusedWindowChanged(current); } private static void Cleanup() => EditorApplication.update -= Tick; #endif private static string _lastWindowType; } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderWindowFocus.cs.meta ================================================ fileFormatVersion: 2 guid: cdd3a4fc755761c42b4a385842caecbc MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Core.meta ================================================ fileFormatVersion: 2 guid: fd43daf252014e319860d77e81a52db8 timeCreated: 1746365393 ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Dev/AssetFinderDefine.cs ================================================ namespace VirtueSky.AssetFinder.Editor { internal static class AssetFinderDefine { internal static bool IsDebugModeEnabled() { string cscPath = GetCscFilePath(); return System.IO.File.Exists(cscPath) && HasDefine(System.IO.File.ReadAllText(cscPath), "AssetFinderDEBUG"); } internal static void ToggleDebugMode(bool enable) { string cscPath = GetCscFilePath(); string content = System.IO.File.Exists(cscPath) ? System.IO.File.ReadAllText(cscPath) : ""; content = enable ? AddDefine(content, "AssetFinderDEBUG") : RemoveDefine(content, "AssetFinderDEBUG"); if (!string.IsNullOrWhiteSpace(content)) { System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(cscPath)); System.IO.File.WriteAllText(cscPath, content); } else if (System.IO.File.Exists(cscPath)) { System.IO.File.Delete(cscPath); } UnityEditor.AssetDatabase.Refresh(); UnityEngine.Debug.Log($"FR2 Developer Mode {(enable ? "enabled" : "disabled")}. Unity will recompile."); } private static string GetCscFilePath() { return System.IO.Path.Combine("Assets", "csc.rsp"); } internal static bool HasDefine(string content, string define) { if (string.IsNullOrWhiteSpace(content)) return false; var defines = ReadDefines(content); return defines.Contains(define); } internal static string AddDefine(string content, string define) { var defines = ReadDefines(content); if (!defines.Contains(define)) { defines.Add(define); } return WriteDefines(defines); } internal static string RemoveDefine(string content, string define) { var defines = ReadDefines(content); defines.Remove(define); return WriteDefines(defines); } private static System.Collections.Generic.List ReadDefines(string content) { var result = new System.Collections.Generic.List(); if (string.IsNullOrWhiteSpace(content)) return result; string[] lines = content.Split('\n'); foreach (string line in lines) { string trimmedLine = line.Trim(); if (trimmedLine.StartsWith("-define:")) { // Extract existing symbols from -define: (same logic as GDK) string definesString = trimmedLine.Substring(8); // Skip "-define:" if (!string.IsNullOrEmpty(definesString)) { result.AddRange(definesString.Split(';')); } } } return result; } private static string WriteDefines(System.Collections.Generic.List defines) { // Clean up empty/whitespace defines var cleanDefines = new System.Collections.Generic.List(); foreach (string define in defines) { string trimmed = define?.Trim(); if (!string.IsNullOrEmpty(trimmed)) { cleanDefines.Add(trimmed); } } // Write exactly like GDK does return cleanDefines.Count > 0 ? $"-define:{string.Join(";", cleanDefines)}" : string.Empty; } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Dev/AssetFinderDefine.cs.meta ================================================ fileFormatVersion: 2 guid: 6012e303bbe76174e8881b5cb101e950 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Dev/AssetFinderDev.cs ================================================ // #define AssetFinderDEV using System; namespace VirtueSky.AssetFinder.Editor { public class AssetFinderDev { public static IDisposable NoLog => new NoLogScope(); private readonly struct NoLogScope : IDisposable { #if AssetFinderDEV internal NoLogScope(bool _) { } public void Dispose() { } #else private readonly bool _saved; internal NoLogScope(bool _) { _saved = UnityEngine.Debug.unityLogger.logEnabled; UnityEngine.Debug.unityLogger.logEnabled = false; } public void Dispose() => UnityEngine.Debug.unityLogger.logEnabled = _saved; #endif } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Dev/AssetFinderDev.cs.meta ================================================ fileFormatVersion: 2 guid: 2e217d3aaf8ffd94d97abbbf9b0e9df5 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Dev/AssetFinderReferenceValidator.cs ================================================ using System.Collections.Generic; using System.Linq; using UnityEditor; using UnityEngine; namespace VirtueSky.AssetFinder.Editor { #if AssetFinderDEV /// /// Comprehensive reference validation system comparing FR2 vs Unity's GetDependencies /// internal class AssetFinderReferenceValidator { private struct ValidationResult { public int totalAssets; public int assetsWithDifferences; public int missingInFR2; public int extraInFR2; public List differences; public Dictionary missingByExtension; public Dictionary extraByExtension; public Dictionary assetTypeIssues; } private struct AssetDifference { public string assetPath; public string guid; public string assetType; public List missingInFR2; // In Unity but not in FR2 public List extraInFR2; // In FR2 but not in Unity public string summary; } private readonly Dictionary unityDependencyCache = new Dictionary(); private readonly System.Text.StringBuilder reportBuilder = new System.Text.StringBuilder(); public void ValidateAllReferences(bool exportToFile = false) { var startTime = System.DateTime.Now; var result = new ValidationResult { differences = new List(), missingByExtension = new Dictionary(), extraByExtension = new Dictionary(), assetTypeIssues = new Dictionary() }; // Clear caches unityDependencyCache.Clear(); reportBuilder.Clear(); // Get all critical assets from FR2 cache var criticalAssets = AssetFinderCache.Api.AssetList .Where(asset => asset != null && !asset.IsMissing && asset.IsCriticalAsset()) .ToList(); result.totalAssets = criticalAssets.Count; AppendToReport($"=== FR2 REFERENCE VALIDATION REPORT ==="); AppendToReport($"Generated: {System.DateTime.Now:yyyy-MM-dd HH:mm:ss}"); AppendToReport($"Total critical assets to analyze: {result.totalAssets}"); AppendToReport(""); AssetFinderLOG.Log($"[AssetFinderVALIDATION] Analyzing {result.totalAssets} critical assets..."); var processedCount = 0; var lastProgressReport = 0; foreach (var asset in criticalAssets) { processedCount++; // Progress reporting (every 10%) var progressPercent = (processedCount * 100) / result.totalAssets; if (progressPercent >= lastProgressReport + 10) { lastProgressReport = progressPercent; AssetFinderLOG.Log($"[AssetFinderVALIDATION] Progress: {progressPercent}% ({processedCount}/{result.totalAssets})"); } var difference = CompareAssetReferences(asset); if (difference.missingInFR2.Count > 0 || difference.extraInFR2.Count > 0) { result.differences.Add(difference); result.assetsWithDifferences++; result.missingInFR2 += difference.missingInFR2.Count; result.extraInFR2 += difference.extraInFR2.Count; // Track by extension and asset type string assetExt = System.IO.Path.GetExtension(asset.assetPath).ToLower(); result.assetTypeIssues[assetExt] = result.assetTypeIssues.GetValueOrDefault(assetExt, 0) + 1; foreach (var missing in difference.missingInFR2) { string depPath = ExtractPathFromDependencyString(missing); string depExt = System.IO.Path.GetExtension(depPath).ToLower(); result.missingByExtension[depExt] = result.missingByExtension.GetValueOrDefault(depExt, 0) + 1; } foreach (var extra in difference.extraInFR2) { string depPath = ExtractPathFromDependencyString(extra); string depExt = System.IO.Path.GetExtension(depPath).ToLower(); result.extraByExtension[depExt] = result.extraByExtension.GetValueOrDefault(depExt, 0) + 1; } } } var duration = System.DateTime.Now - startTime; LogValidationResults(result, duration, exportToFile); } private AssetDifference CompareAssetReferences(AssetFinderAsset asset) { var difference = new AssetDifference { assetPath = asset.assetPath, guid = asset.guid, assetType = asset.type.ToString(), missingInFR2 = new List(), extraInFR2 = new List() }; try { // Get Unity's dependencies (with caching) string[] unityDeps; if (!unityDependencyCache.TryGetValue(asset.assetPath, out unityDeps)) { unityDeps = AssetDatabase.GetDependencies(asset.assetPath, false); // Direct dependencies only unityDependencyCache[asset.assetPath] = unityDeps; } var unityGuids = new HashSet(); foreach (string depPath in unityDeps) { if (depPath == asset.assetPath) continue; // Skip self-reference string depGuid = AssetDatabase.AssetPathToGUID(depPath); if (!string.IsNullOrEmpty(depGuid)) { unityGuids.Add(depGuid); } } // Get FR2's dependencies var fr2Guids = new HashSet(); if (asset.UseGUIDs != null) { fr2Guids.UnionWith(asset.UseGUIDs.Keys); } // Find differences foreach (string unityGuid in unityGuids) { if (!fr2Guids.Contains(unityGuid)) { string depPath = AssetDatabase.GUIDToAssetPath(unityGuid); difference.missingInFR2.Add($"{unityGuid} ({depPath})"); } } foreach (string fr2Guid in fr2Guids) { if (!unityGuids.Contains(fr2Guid)) { string depPath = AssetDatabase.GUIDToAssetPath(fr2Guid); difference.extraInFR2.Add($"{fr2Guid} ({depPath})"); } } // Create summary if (difference.missingInFR2.Count > 0 || difference.extraInFR2.Count > 0) { difference.summary = $"Missing: {difference.missingInFR2.Count}, Extra: {difference.extraInFR2.Count}"; } } catch (System.Exception e) { difference.summary = $"Error during comparison: {e.Message}"; } return difference; } private void LogValidationResults(ValidationResult result, System.TimeSpan duration, bool exportToFile) { AppendToReport($"Analysis completed in {duration.TotalSeconds:F2} seconds"); AppendToReport($"Assets with differences: {result.assetsWithDifferences}"); AppendToReport($"Total missing references in FR2: {result.missingInFR2}"); AppendToReport($"Total extra references in FR2: {result.extraInFR2}"); AppendToReport(""); if (result.assetsWithDifferences == 0) { AppendToReport("🎉 Perfect match! FR2 and Unity have identical reference detection."); AssetFinderLOG.Log("🎉 Perfect match! FR2 and Unity have identical reference detection."); } else { float accuracy = ((result.totalAssets - result.assetsWithDifferences) * 100f / result.totalAssets); AppendToReport($"Accuracy: {accuracy:F1}%"); AssetFinderLOG.Log($"[AssetFinderVALIDATION] Accuracy: {accuracy:F1}%"); GenerateDetailedReport(result); } if (exportToFile) { string filePath = System.IO.Path.Combine(Application.dataPath, "../AssetFinderValidation_Report.txt"); System.IO.File.WriteAllText(filePath, reportBuilder.ToString()); AssetFinderLOG.Log($"[AssetFinderVALIDATION] Detailed report exported to: {filePath}"); } else { // Console output (limited) AssetFinderLOG.Log("=== FR2 REFERENCE VALIDATION RESULTS ==="); AssetFinderLOG.Log($"Analysis completed in {duration.TotalSeconds:F2} seconds"); AssetFinderLOG.Log($"Total assets analyzed: {result.totalAssets}"); AssetFinderLOG.Log($"Assets with differences: {result.assetsWithDifferences}"); if (result.assetsWithDifferences > 0) { AssetFinderLOG.Log($"Accuracy: {((result.totalAssets - result.assetsWithDifferences) * 100f / result.totalAssets):F1}%"); AssetFinderLOG.Log("Use 'Validate References (Export to File)' for detailed analysis."); } } } private void GenerateDetailedReport(ValidationResult result) { AppendToReport("=== TOP PROBLEMATIC ASSET TYPES ==="); foreach (var kvp in result.assetTypeIssues.OrderByDescending(x => x.Value).Take(10)) { AppendToReport($"{kvp.Key}: {kvp.Value} assets with differences"); } AppendToReport(""); AppendToReport("=== MOST COMMONLY MISSED DEPENDENCY TYPES ==="); foreach (var kvp in result.missingByExtension.OrderByDescending(x => x.Value).Take(10)) { AppendToReport($"{kvp.Key}: {kvp.Value} instances"); } AppendToReport(""); AppendToReport("=== MOST COMMONLY OVER-DETECTED TYPES ==="); foreach (var kvp in result.extraByExtension.OrderByDescending(x => x.Value).Take(10)) { AppendToReport($"{kvp.Key}: {kvp.Value} instances"); } AppendToReport(""); AppendToReport("=== DETAILED DIFFERENCES ==="); var maxDetailsToShow = Mathf.Min(50, result.differences.Count); if (result.differences.Count > maxDetailsToShow) { AppendToReport($"Showing first {maxDetailsToShow} differences (out of {result.differences.Count} total):"); } for (int i = 0; i < maxDetailsToShow; i++) { var diff = result.differences[i]; AppendToReport($"\n[{i + 1}] {diff.assetPath}"); AppendToReport($" Type: {diff.assetType} | GUID: {diff.guid}"); AppendToReport($" Summary: {diff.summary}"); if (diff.missingInFR2.Count > 0) { AppendToReport($" Missing in FR2 ({diff.missingInFR2.Count}):"); foreach (var missing in diff.missingInFR2.Take(5)) { AppendToReport($" - {missing}"); } if (diff.missingInFR2.Count > 5) { AppendToReport($" ... and {diff.missingInFR2.Count - 5} more"); } } if (diff.extraInFR2.Count > 0) { AppendToReport($" Extra in FR2 ({diff.extraInFR2.Count}):"); foreach (var extra in diff.extraInFR2.Take(5)) { AppendToReport($" - {extra}"); } if (diff.extraInFR2.Count > 5) { AppendToReport($" ... and {diff.extraInFR2.Count - 5} more"); } } } } private void AppendToReport(string line) { reportBuilder.AppendLine(line); } private string ExtractPathFromDependencyString(string depString) { // Extract path from format "guid (path)" int startParen = depString.IndexOf('('); int endParen = depString.IndexOf(')', startParen); if (startParen >= 0 && endParen > startParen) { return depString.Substring(startParen + 1, endParen - startParen - 1); } return depString; } private void AnalyzeValidationPatterns(List differences) { // This method is now integrated into GenerateDetailedReport } } #endif } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Dev/AssetFinderReferenceValidator.cs.meta ================================================ fileFormatVersion: 2 guid: 95909f9cceec2c94d98b1f9a061b26d3 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Dev/AssetFinderWindowAll.Validator.cs ================================================ using UnityEditor; using UnityEngine; namespace VirtueSky.AssetFinder.Editor { internal partial class AssetFinderWindowAll { public override void AddToCustomMenu(GenericMenu menu) { #if AssetFinderDEV menu.AddItem(new GUIContent("Refresh Cache"), false, () => AssetFinderCache.Api.Check4Changes(true)); menu.AddItem(new GUIContent("Validate References vs Unity"), false, ()=>ValidateReferencesVsUnity()); menu.AddItem(new GUIContent("Validate References (Export to File)"), false, () => ValidateReferencesVsUnity(true)); menu.AddItem(new GUIContent("Debug Selected Assets"), false, DebugSelectedAssets); #endif } #if AssetFinderDEV private void ValidateReferencesVsUnity(bool exportToFile = false) { if (!AssetFinderCache.isReady) { AssetFinderLOG.LogWarning("[AssetFinderVALIDATION] Cache not ready. Please wait for cache to finish loading."); return; } if (exportToFile) { AssetFinderLOG.Log("[AssetFinderVALIDATION] Starting validation with file export..."); } else { AssetFinderLOG.Log("[AssetFinderVALIDATION] Starting comprehensive reference validation against Unity's GetDependencies..."); } var validator = new AssetFinderReferenceValidator(); validator.ValidateAllReferences(exportToFile); } private void DebugSelectedAssets() { if (Selection.objects == null || Selection.objects.Length == 0) { AssetFinderLOG.LogWarning("[AssetFinderDEBUG] No objects selected for debugging"); return; } foreach (var obj in Selection.objects) { string path = AssetDatabase.GetAssetPath(obj); if (string.IsNullOrEmpty(path)) continue; string guid = AssetDatabase.AssetPathToGUID(path); Debug.Log($"[AssetFinderDEBUG] === {obj.name} ({guid}) ==="); if (!AssetFinderCache.isReady) { AssetFinderLOG.LogWarning("[AssetFinderDEBUG] Cache not ready!"); continue; } AssetFinderAsset asset = AssetFinderCache.Api.Get(guid); if (asset == null) { AssetFinderLOG.LogWarning("[AssetFinderDEBUG] Asset not found in cache!"); continue; } Debug.Log($"Type: {asset.type} | Critical: {asset.IsCriticalAsset()} | Extension: {asset.extension}"); AssetFinderLOG.Log($"Uses: {asset.UseGUIDs?.Count ?? 0} | UsedBy: {asset.UsedByMap?.Count ?? 0}"); Debug.Log($"InAssetList: {AssetFinderCache.Api.AssetList?.Contains(asset) ?? false} | Dirty: {asset.isDirty}"); } } #endif } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Dev/AssetFinderWindowAll.Validator.cs.meta ================================================ fileFormatVersion: 2 guid: dd971677ed211ef41826f4ab2d3bb028 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Dev.meta ================================================ fileFormatVersion: 2 guid: d6d7bf6fb14b44c697ed962d9ca4fac6 timeCreated: 1753192840 ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Drawer/AssetFinderAddressableDrawer.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using UnityEditor; using UnityEngine; namespace VirtueSky.AssetFinder.Editor { internal class AssetFinderAddressableDrawer : IRefDraw { private const string AUTO_DEPEND_TITLE = "(Auto dependency)"; private readonly Dictionary AsmMessage = new Dictionary { { AssetFinderAddressable.ASMStatus.None, "-" }, { AssetFinderAddressable.ASMStatus.AsmNotFound, "Addressable Package not imported!" }, { AssetFinderAddressable.ASMStatus.TypeNotFound, "Addressable Classes not found (addressable library code changed?)!" }, { AssetFinderAddressable.ASMStatus.FieldNotFound, "Addressable Fields not found (addressable library code changed?)!" }, { AssetFinderAddressable.ASMStatus.AsmOK, "-" } }; internal readonly AssetFinderRefDrawer drawer; internal readonly Dictionary map = new Dictionary(); private readonly Dictionary ProjectStatusMessage = new Dictionary { { AssetFinderAddressable.ProjectStatus.None, "-" }, { AssetFinderAddressable.ProjectStatus.NoSettings, "No Addressables Settings found!\nOpen [Window/Asset Management/Addressables/Groups] to create new Addressables Settings!\n \n" }, { AssetFinderAddressable.ProjectStatus.NoGroup, "No AssetBundle Group created!" }, { AssetFinderAddressable.ProjectStatus.Ok, "-" } }; private bool dirty; internal List groups; internal float maxWidth; internal Dictionary refs; public AssetFinderAddressableDrawer(IWindow window, Func getSortMode, Func getGroupMode) { this.window = window; drawer = new AssetFinderRefDrawer(new AssetFinderRefDrawer.AssetDrawingConfig { window = window, getSortMode = getSortMode, getGroupMode = getGroupMode, showFullPath = false, showFileSize = true, showExtension = true, showUsageType = false, showAssetBundleName = false, showAtlasName = false }) { messageNoRefs = "No Addressable Asset", messageEmpty = "No Addressable Asset", customGetGroup = GetGroup, customDrawGroupLabel = DrawGroupLabel, beforeItemDraw = BeforeDrawItem, afterItemDraw = AfterDrawItem }; dirty = true; drawer.SetDirty(); } public IWindow window { get; set; } public int ElementCount() { return refs?.Count ?? 0; } public bool Draw(Rect rect) { if (dirty) RefreshView(); if (refs == null) return false; rect.yMax -= 24f; bool result = drawer.Draw(rect); Rect btnRect = rect; btnRect.xMin = btnRect.xMax - 24f; btnRect.yMin = btnRect.yMax; btnRect.height = 24f; if (GUI.Button(btnRect, AssetFinderIcon.Refresh.image)) { AssetFinderAddressable.Scan(); RefreshView(); } return result; } public bool DrawLayout() { if (dirty) RefreshView(); return drawer.DrawLayout(); } private string GetGroup(AssetFinderRef rf) { return rf.group; } private void DrawGroupLabel(Rect r, string label, int childCount) { Color c = GUI.contentColor; if (label == AUTO_DEPEND_TITLE) { Color c1 = c; c1.a = 0.5f; GUI.contentColor = c1; } GUI.Label(r, AssetFinderGUIContent.FromString(label), EditorStyles.boldLabel); GUI.contentColor = c; } private void BeforeDrawItem(Rect r, AssetFinderRef rf) { string guid = rf.asset.guid; if (map.TryGetValue(guid, out AssetFinderAddressable.AddressInfo address)) return; Color c = GUI.contentColor; c.a = 0.35f; GUI.contentColor = c; } private void AfterDrawItem(Rect r, AssetFinderRef rf) { string guid = rf.asset.guid; if (!map.TryGetValue(guid, out AssetFinderAddressable.AddressInfo address)) { Color c2 = GUI.contentColor; c2.a = 1f; GUI.contentColor = c2; return; } Color c = GUI.contentColor; Color c1 = c; c1.a = 0.5f; GUI.contentColor = c1; { r.xMin = r.xMax - maxWidth; GUI.Label(r, AssetFinderGUIContent.FromString(address.address), EditorStyles.miniLabel); } GUI.contentColor = c; } public void SetDirty() { dirty = true; drawer.SetDirty(); } public void RefreshView() { if (refs == null) refs = new Dictionary(); refs.Clear(); Dictionary addresses = AssetFinderAddressable.GetAddresses(); if (AssetFinderAddressable.asmStatus != AssetFinderAddressable.ASMStatus.AsmOK) { drawer.messageNoRefs = AsmMessage[AssetFinderAddressable.asmStatus]; } else if (AssetFinderAddressable.projectStatus != AssetFinderAddressable.ProjectStatus.Ok) { drawer.messageNoRefs = ProjectStatusMessage[AssetFinderAddressable.projectStatus]; } drawer.messageEmpty = drawer.messageNoRefs; if (addresses == null) addresses = new Dictionary(); groups = addresses.Keys.ToList(); map.Clear(); if (addresses.Count > 0) { var maxLengthGroup = string.Empty; foreach (KeyValuePair kvp in addresses) { foreach (string guid in kvp.Value.assetGUIDs) { if (refs.ContainsKey(guid)) continue; AssetFinderAsset asset = AssetFinderCache.Api.Get(guid); refs.Add(guid, new AssetFinderRef(0, 1, asset, null, null) { isSceneRef = false, group = kvp.Value.bundleGroup }); map.Add(guid, kvp.Value); if (maxLengthGroup.Length < kvp.Value.address.Length) { maxLengthGroup = kvp.Value.address; } } foreach (string guid in kvp.Value.childGUIDs) { if (refs.ContainsKey(guid)) continue; AssetFinderAsset asset = AssetFinderCache.Api.Get(guid); refs.Add(guid, new AssetFinderRef(0, 1, asset, null, null) { isSceneRef = false, group = kvp.Value.bundleGroup }); map.Add(guid, kvp.Value); if (maxLengthGroup.Length < kvp.Value.address.Length) { maxLengthGroup = kvp.Value.address; } } } var miniLabelStyle = EditorStyles.miniLabel ?? new GUIStyle(); maxWidth = miniLabelStyle.CalcSize( AssetFinderGUIContent.FromString(maxLengthGroup) ).x + 16f; // Find usage Dictionary usages = AssetFinderRef.FindUsage(map.Keys.ToArray()); foreach (KeyValuePair kvp in usages) { if (refs.ContainsKey(kvp.Key)) continue; AssetFinderRef v = kvp.Value; // do not take script if (v.asset.IsScript) continue; if (v.asset.IsExcluded) continue; refs.Add(kvp.Key, kvp.Value); kvp.Value.depth = 1; kvp.Value.group = AUTO_DEPEND_TITLE; } } dirty = false; drawer.SetRefs(refs); } internal void RefreshSort() { drawer.RefreshSort(); } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Drawer/AssetFinderAddressableDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: d1f842a83edda6e42a6c4ea4dc024049 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Drawer/AssetFinderAssetGroup.cs ================================================ using System.Collections.Generic; namespace VirtueSky.AssetFinder.Editor { internal class AssetFinderAssetGroup { public string name; public HashSet extension; public AssetFinderAssetGroup(string name, params string[] exts) { this.name = name; extension = new HashSet(); for (var i = 0; i < exts.Length; i++) { extension.Add(exts[i]); } } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Drawer/AssetFinderAssetGroup.cs.meta ================================================ fileFormatVersion: 2 guid: bd3abcb0505d46544820add49a5c7377 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Drawer/AssetFinderAssetGroupDrawer.cs ================================================ using UnityEditor; using UnityEngine; namespace VirtueSky.AssetFinder.Editor { internal static class AssetFinderAssetGroupDrawer { // ------------------------------- STATIC ----------------------------- internal static readonly AssetFinderAssetGroup[] FILTERS = { new AssetFinderAssetGroup("Scene", ".unity"), new AssetFinderAssetGroup("Prefab", ".prefab"), new AssetFinderAssetGroup("Model", ".3df", ".3dm", ".3dmf", ".3dv", ".3dx", ".c5d", ".lwo", ".lws", ".ma", ".mb", ".mesh", ".vrl", ".wrl", ".wrz", ".fbx", ".dae", ".3ds", ".dxf", ".obj", ".skp", ".max", ".blend"), new AssetFinderAssetGroup("Material", ".mat", ".cubemap", ".physicsmaterial"), new AssetFinderAssetGroup("Texture", ".ai", ".apng", ".png", ".bmp", ".cdr", ".dib", ".eps", ".exif", ".ico", ".icon", ".j", ".j2c", ".j2k", ".jas", ".jiff", ".jng", ".jp2", ".jpc", ".jpe", ".jpeg", ".jpf", ".jpg", "jpw", "jpx", "jtf", ".mac", ".omf", ".qif", ".qti", "qtif", ".tex", ".tfw", ".tga", ".tif", ".tiff", ".wmf", ".psd", ".exr", ".rendertexture"), new AssetFinderAssetGroup("Video", ".asf", ".asx", ".avi", ".dat", ".divx", ".dvx", ".mlv", ".m2l", ".m2t", ".m2ts", ".m2v", ".m4e", ".m4v", "mjp", ".mov", ".movie", ".mp21", ".mp4", ".mpe", ".mpeg", ".mpg", ".mpv2", ".ogm", ".qt", ".rm", ".rmvb", ".wmv", ".xvid", ".flv"), new AssetFinderAssetGroup("Audio", ".mp3", ".wav", ".ogg", ".aif", ".aiff", ".mod", ".it", ".s3m", ".xm"), new AssetFinderAssetGroup("Script", ".cs", ".js", ".boo", ".h"), new AssetFinderAssetGroup("Text", ".txt", ".json", ".xml", ".bytes", ".sql"), new AssetFinderAssetGroup("Shader", ".shader", ".cginc", ".shadervariants"), new AssetFinderAssetGroup("Animation", ".anim", ".controller", ".overridecontroller", ".mask"), new AssetFinderAssetGroup("Font", ".ttf", ".otf", ".dfont", ".ttc"), new AssetFinderAssetGroup("Unity Asset", ".asset", ".guiskin", ".flare", ".fontsettings", ".prefs", ".playable", ".signal"), new AssetFinderAssetGroup("Others") // }; private static AssetFinderIgnoreDrawer _ignore; private static AssetFinderIgnoreDrawer ignore { get { if (_ignore == null) _ignore = new AssetFinderIgnoreDrawer(); return _ignore; } } public static int GetIndex(string ext) { // Normalize extension to lowercase for case-insensitive comparison string normalizedExt = ext?.ToLowerInvariant() ?? ""; for (var i = 0; i < FILTERS.Length - 1; i++) { if (FILTERS[i].extension.Contains(normalizedExt)) return i; } return FILTERS.Length - 1; //Others } public static bool DrawSearchFilter() { int n = FILTERS.Length; var nCols = 4; int nRows = Mathf.CeilToInt(n / (float)nCols); var result = false; EditorGUILayout.BeginHorizontal(EditorStyles.toolbar); { if (GUILayout.Button("All", EditorStyles.toolbarButton) && !AssetFinderSetting.IsIncludeAllType()) { AssetFinderSetting.IncludeAllType(); result = true; } if (GUILayout.Button("None", EditorStyles.toolbarButton) && (AssetFinderSetting.GetExcludeType() != -1)) { AssetFinderSetting.ExcludeAllType(); result = true; } } EditorGUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); for (var i = 0; i < nCols; i++) { GUILayout.BeginVertical(); for (var j = 0; j < nRows; j++) { int idx = i * nCols + j; if (idx >= n) break; bool s = !AssetFinderSetting.IsTypeExcluded(idx); bool s1 = GUILayout.Toggle(s, FILTERS[idx].name); if (s1 != s) { result = true; AssetFinderSetting.ToggleTypeExclude(idx); } } GUILayout.EndVertical(); if ((i + 1) * nCols >= n) break; } GUILayout.EndHorizontal(); return result; } public static void SetDirtyIgnore() { ignore.SetDirty(); } public static bool DrawIgnoreFolder() { var change = false; ignore.Draw(); return change; } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Drawer/AssetFinderAssetGroupDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: 253072b20ae7c4f4d8119fcba52ca790 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Drawer/AssetFinderAssetOrganizer.cs ================================================ using System; using System.Collections.Generic; using System.IO; using System.Linq; using UnityEditor; using UnityEngine; using UnityObject = UnityEngine.Object; namespace VirtueSky.AssetFinder.Editor { internal class AssetFinderAssetOrganizer : IRefDraw { // Processing state and dependencies private readonly IWindow _window; private bool _isProcessing; private float _progress; private string _currentFolderPath; private HashSet _foldersToProcess = new HashSet(); private Dictionary> _assetsToMove = new Dictionary>(); private List _plannedMoves = new List(); // Results tracking private Dictionary _organizedFolders = new Dictionary(); private List _errorAssets = new List(); private string _reportTitle; // Settings backup private AssetFinderAutoRefreshMode _originalAutoRefreshMode; // Asset classification private static readonly string[] SpecialFolders = {"/Editor/", "/Resources/", "/StreamingAssets/", "/Gizmos/", "/Plugins/", "/Standard Assets/"}; private static readonly string[] ScriptExtensions = { ".cs", ".js", ".boo" }; private HashSet _spriteAtlasFolders = new HashSet(); private Dictionary _spriteAtlasInfo = new Dictionary(); private Dictionary _spineAssetInfo = new Dictionary(); private HashSet _spineAssets = new HashSet(); internal AssetFinderAssetOrganizer(IWindow window, Func getSort, Func getGroup) { _window = window; } public IWindow window => _window; public int ElementCount() { return _organizedFolders.Count + _errorAssets.Count; } public bool Draw(Rect rect) { GUI.BeginClip(rect); GUILayout.BeginArea(new Rect(0, 0, rect.width, rect.height)); bool result = DrawLayout(); GUILayout.EndArea(); GUI.EndClip(); return result; } public bool DrawLayout() { GUILayout.BeginVertical(); { if (_isProcessing) { DrawProgressBar(); } else { DrawSelectedFolders(); GUILayout.Space(10); bool hasFoldersSelected = _foldersToProcess.Count > 0; GUI.enabled = hasFoldersSelected; if (GUILayout.Button("Organize Selected Folder" + (hasFoldersSelected && _foldersToProcess.Count > 1 ? "s" : ""), AssetFinderTheme.Current.ActionButtonHeight)) { StartProcessing(); } GUI.enabled = true; if (!hasFoldersSelected) { EditorGUILayout.HelpBox("Please select one or more folders in the Project panel to organize.", MessageType.Info); } if (!string.IsNullOrEmpty(_reportTitle)) { EditorGUILayout.HelpBox(_reportTitle, MessageType.Info); } if (_organizedFolders.Count > 0) { GUILayout.Space(10); EditorGUILayout.LabelField("Organized Assets:", EditorStyles.boldLabel); GUILayout.BeginVertical(EditorStyles.helpBox); foreach (var folder in _organizedFolders.OrderBy(f => f.Key)) { EditorGUILayout.LabelField($"{folder.Key}: {folder.Value} assets", EditorStyles.miniLabel); } GUILayout.EndVertical(); } if (_errorAssets.Count > 0) { GUILayout.Space(10); EditorGUILayout.LabelField("Errors:", EditorStyles.boldLabel); GUILayout.BeginVertical(EditorStyles.helpBox); foreach (string error in _errorAssets.Take(10)) { EditorGUILayout.LabelField(error, EditorStyles.miniLabel); } if (_errorAssets.Count > 10) { EditorGUILayout.LabelField($"...and {_errorAssets.Count - 10} more", EditorStyles.miniLabel); } GUILayout.EndVertical(); } } } GUILayout.EndVertical(); GUILayout.FlexibleSpace(); return true; } private void DrawSelectedFolders() { _foldersToProcess.Clear(); foreach (UnityObject obj in Selection.objects) { string path = AssetDatabase.GetAssetPath(obj); if (string.IsNullOrEmpty(path)) continue; if (AssetDatabase.IsValidFolder(path)) { _foldersToProcess.Add(path); } } CleanupSelectionHierarchy(); if (_foldersToProcess.Count > 0) { EditorGUILayout.LabelField("Selected Folders:", EditorStyles.boldLabel); GUILayout.BeginVertical(EditorStyles.helpBox); foreach (string folder in _foldersToProcess.OrderBy(f => f)) { EditorGUILayout.LabelField(folder, EditorStyles.miniLabel); } GUILayout.EndVertical(); } } private void CleanupSelectionHierarchy() { var foldersToRemove = new HashSet(); foreach (string folder in _foldersToProcess) { foreach (string otherFolder in _foldersToProcess) { if (folder != otherFolder && folder.StartsWith(otherFolder + "/")) { foldersToRemove.Add(folder); } } } foreach (string folderToRemove in foldersToRemove) { _foldersToProcess.Remove(folderToRemove); } } private void DrawProgressBar() { EditorGUILayout.Space(); EditorGUILayout.LabelField("Organizing assets...", EditorStyles.boldLabel); Rect rect = AssetFinderTheme.Current.GetProgressBarRect(); EditorGUI.ProgressBar(rect, _progress, _currentFolderPath); EditorGUILayout.Space(); if (GUILayout.Button("Cancel", AssetFinderTheme.Current.CancelButtonHeight)) { CancelProcessing(); } } private void StartProcessing() { DisableAutoRefresh(); _isProcessing = true; _progress = 0f; _currentFolderPath = string.Empty; _organizedFolders.Clear(); _errorAssets.Clear(); _assetsToMove.Clear(); _plannedMoves.Clear(); _reportTitle = null; _spriteAtlasFolders.Clear(); _spriteAtlasInfo.Clear(); _spineAssetInfo.Clear(); _spineAssets.Clear(); AnalyzeSpineAssets(); AnalyzeSpriteAtlases(); foreach (string folderPath in _foldersToProcess) { AnalyzeFolder(folderPath); } CleanupEmptyMoveEntries(); var scriptMoves = new Dictionary>(); var nonScriptMoves = new Dictionary>(); foreach (var kvp in _assetsToMove) { var scripts = new List(); var nonScripts = new List(); foreach (var assetPath in kvp.Value) { string ext = Path.GetExtension(assetPath).ToLowerInvariant(); if (ScriptExtensions.Contains(ext)) scripts.Add(assetPath); else nonScripts.Add(assetPath); } if (nonScripts.Count > 0) nonScriptMoves[kvp.Key] = nonScripts; if (scripts.Count > 0) scriptMoves[kvp.Key] = scripts; } _assetsToMove.Clear(); foreach (var kvp in nonScriptMoves) { _assetsToMove[kvp.Key] = kvp.Value; } foreach (var kvp in scriptMoves) { _assetsToMove[kvp.Key] = kvp.Value; } PlanAllMoves(); if (_plannedMoves.Count == 0) { _reportTitle = "No assets needed to be organized."; CleanupAfterProcessing(); return; } EditorApplication.update -= ProcessNextBatch; EditorApplication.update += ProcessNextBatch; } private void CancelProcessing() { _isProcessing = false; CleanupAfterProcessing(); } private void CleanupAfterProcessing() { _isProcessing = false; RestoreAutoRefreshMode(); AssetFinderDeleteEmptyFolder.DeleteAllEmptyFoldersRecursive("Assets"); AssetDatabase.Refresh(); _window.Repaint(); } private void DisableAutoRefresh() { _originalAutoRefreshMode = AssetFinderSettingExt.autoRefreshMode; AssetFinderSettingExt.autoRefreshMode = AssetFinderAutoRefreshMode.Off; } private void RestoreAutoRefreshMode() { AssetFinderSettingExt.autoRefreshMode = _originalAutoRefreshMode; } private void AnalyzeSpineAssets() { string[] spineGUIDs = AssetDatabase.FindAssets("t:SkeletonDataAsset"); foreach (string guid in spineGUIDs) { string skeletonPath = AssetDatabase.GUIDToAssetPath(guid); UnityObject skeletonAsset = AssetDatabase.LoadAssetAtPath(skeletonPath); if (skeletonAsset != null) { string skeletonName = Path.GetFileNameWithoutExtension(skeletonPath); if (skeletonName.EndsWith("_SkeletonData")) { skeletonName = skeletonName.Substring(0, skeletonName.Length - "_SkeletonData".Length); } var spineInfo = new SpineAssetInfo { skeletonPath = skeletonPath, spineName = skeletonName }; spineInfo.assets.Add(skeletonPath); _spineAssets.Add(skeletonPath); SerializedObject so = new SerializedObject(skeletonAsset); SerializedProperty iterator = so.GetIterator(); while (iterator.NextVisible(true)) { if (iterator.propertyType == SerializedPropertyType.ObjectReference && iterator.objectReferenceValue != null) { string refPath = AssetDatabase.GetAssetPath(iterator.objectReferenceValue); if (!string.IsNullOrEmpty(refPath) && refPath != skeletonPath) { spineInfo.assets.Add(refPath); _spineAssets.Add(refPath); } } } _spineAssetInfo[skeletonPath] = spineInfo; } } } private void AnalyzeSpriteAtlases() { string[] atlasGUIDs = AssetDatabase.FindAssets("t:SpriteAtlas"); foreach (string guid in atlasGUIDs) { string atlasPath = AssetDatabase.GUIDToAssetPath(guid); UnityObject atlasAsset = AssetDatabase.LoadAssetAtPath(atlasPath); if (atlasAsset != null) { var atlasInfo = new SpriteAtlasInfo { atlasPath = atlasPath }; SerializedObject so = new SerializedObject(atlasAsset); SerializedProperty objectsForPacking = so.FindProperty("m_EditorData.packables"); if (objectsForPacking != null && objectsForPacking.isArray) { for (int i = 0; i < objectsForPacking.arraySize; i++) { SerializedProperty element = objectsForPacking.GetArrayElementAtIndex(i); UnityObject obj = element.objectReferenceValue; if (obj != null) { string objPath = AssetDatabase.GetAssetPath(obj); if (AssetDatabase.IsValidFolder(objPath)) { _spriteAtlasFolders.Add(objPath); atlasInfo.folders.Add(objPath); } else { atlasInfo.sprites.Add(objPath); } } } } _spriteAtlasInfo[atlasPath] = atlasInfo; } } } private void AnalyzeFolder(string folderPath) { if (string.IsNullOrEmpty(folderPath)) return; if (!AssetDatabase.IsValidFolder(folderPath)) return; string[] assetGUIDs = AssetDatabase.FindAssets("*", new[] { folderPath }); foreach (string guid in assetGUIDs) { string assetPath = AssetDatabase.GUIDToAssetPath(guid); if (AssetDatabase.IsValidFolder(assetPath) || assetPath.EndsWith(".meta")) continue; string assetPathLower = assetPath.Replace('\\', '/').ToLowerInvariant(); bool inSpecial = SpecialFolders.Any(sf => assetPathLower.Contains(sf.ToLowerInvariant())); if (inSpecial) continue; if (IsSpineAsset(assetPath)) continue; if (IsInSpriteAtlasFolder(assetPath)) continue; string extension = Path.GetExtension(assetPath).ToLowerInvariant(); string folderType = DetermineFolderType(assetPath, extension); string targetFolderPath = $"{folderPath}/{folderType}"; string currentAssetFolder = Path.GetDirectoryName(assetPath); if (NormalizePath(currentAssetFolder).Equals(NormalizePath(targetFolderPath), StringComparison.OrdinalIgnoreCase)) continue; string key = folderPath + "|" + folderType; if (!_assetsToMove.ContainsKey(key)) _assetsToMove[key] = new List(); _assetsToMove[key].Add(assetPath); } foreach (var spineInfo in _spineAssetInfo.Values) { bool anyAssetInFolder = spineInfo.assets.Any(asset => asset.StartsWith(folderPath + "/") || asset == folderPath); if (anyAssetInFolder) { string targetPath = folderPath + "/Spines/" + spineInfo.spineName; string key = targetPath + "|SPINE_GROUP|" + spineInfo.spineName; if (!_assetsToMove.ContainsKey(key)) _assetsToMove[key] = new List(); foreach (string asset in spineInfo.assets) { if (asset.StartsWith(folderPath + "/") || asset == folderPath) { string currentAssetFolder = Path.GetDirectoryName(asset); if (!NormalizePath(currentAssetFolder).Equals(NormalizePath(targetPath), StringComparison.OrdinalIgnoreCase)) { _assetsToMove[key].Add(asset); } } } } } foreach (var atlasInfo in _spriteAtlasInfo.Values) { if (atlasInfo.atlasPath.StartsWith(folderPath + "/") || atlasInfo.atlasPath == folderPath) { string atlasName = Path.GetFileNameWithoutExtension(atlasInfo.atlasPath); string targetPath = folderPath + "/SpriteAtlas"; string currentAtlasFolder = Path.GetDirectoryName(atlasInfo.atlasPath); if (!NormalizePath(currentAtlasFolder).Equals(NormalizePath(targetPath), StringComparison.OrdinalIgnoreCase)) { string atlasKey = targetPath + "|ATLAS|" + atlasName; if (!_assetsToMove.ContainsKey(atlasKey)) _assetsToMove[atlasKey] = new List(); _assetsToMove[atlasKey].Add(atlasInfo.atlasPath); } if (atlasInfo.folders.Count == 1 && atlasInfo.sprites.Count == 0) { string singleFolder = atlasInfo.folders[0]; if (singleFolder.StartsWith(folderPath + "/") || singleFolder == folderPath) { string expectedFolderPath = Path.Combine(targetPath, atlasName); if (!NormalizePath(singleFolder).Equals(NormalizePath(expectedFolderPath), StringComparison.OrdinalIgnoreCase)) { string folderKey = targetPath + "|ATLAS_FOLDER|" + atlasName; if (!_assetsToMove.ContainsKey(folderKey)) _assetsToMove[folderKey] = new List(); _assetsToMove[folderKey].Add(singleFolder); } } } } } } private bool IsSpineAsset(string assetPath) { return _spineAssets.Contains(assetPath); } private bool IsInSpriteAtlasFolder(string assetPath) { return _spriteAtlasFolders.Any(folder => assetPath.StartsWith(folder + "/")); } private string DetermineFolderType(string assetPath, string extension) { if (extension == ".shadervariants") { return "Shaders"; } if (extension == ".lighting") { return "Scenes"; } if (extension == ".asset") { Type assetType = AssetDatabase.GetMainAssetTypeAtPath(assetPath); if (assetType != null) { string typeName = assetType.Name; if (typeName == "LightingDataAsset" || typeName == "LightingSettings") { return "Scenes"; } if (typeName == "TMPro_FontAsset" || typeName.Contains("FontAsset")) { return "Fonts"; } if (typeName == "Mesh") { return "Models"; } if (typeName == "AnimationClip") { return "Animations"; } } } if (IsTextureImportedAsSprite(assetPath)) { return "Sprites"; } string folderType = GetAssetFolderType(extension); if (folderType == "Others") { Type mainType = AssetDatabase.GetMainAssetTypeAtPath(assetPath); if (mainType != null) { string typeName = mainType.Name; string specialType = GetAssetFolderTypeByTypeName(typeName); if (specialType != null) folderType = specialType; else folderType = typeName; } } return folderType; } private bool IsTextureImportedAsSprite(string assetPath) { AssetImporter importer = AssetImporter.GetAtPath(assetPath); if (importer is TextureImporter textureImporter) { return textureImporter.textureType == TextureImporterType.Sprite; } return false; } private string GetAssetFolderTypeByTypeName(string typeName) { for (int i = 0; i < AssetFinderAssetGroupDrawer.FILTERS.Length - 1; i++) { AssetFinderAssetGroup filter = AssetFinderAssetGroupDrawer.FILTERS[i]; if (!string.IsNullOrEmpty(filter.name) && filter.name.Equals(typeName, StringComparison.OrdinalIgnoreCase)) { return filter.name + "s"; } } return null; } private void PlanAllMoves() { var planned = new List(); var usedNames = new HashSet(StringComparer.OrdinalIgnoreCase); foreach (var kvp in _assetsToMove) { string[] parts = kvp.Key.Split('|'); string parentFolder = parts[0]; string folderType = parts[1]; if (parts.Length > 2 && (parts[1] == "SPINE_GROUP" || parts[1] == "ATLAS" || parts[1] == "ATLAS_FOLDER")) { string newName = parts[2]; string targetFolderPath = parentFolder; string absTargetFolder = AssetPathToAbs(targetFolderPath); if (!Directory.Exists(absTargetFolder)) Directory.CreateDirectory(absTargetFolder); if (parts[1] == "SPINE_GROUP") { foreach (string assetPath in kvp.Value) { string srcAbs = AssetPathToAbs(assetPath); string fileName = Path.GetFileName(assetPath); string dstAbs = Path.Combine(absTargetFolder, fileName); if (NormalizePath(srcAbs).Equals(NormalizePath(dstAbs), StringComparison.OrdinalIgnoreCase)) continue; planned.Add(new PlannedMove { srcAsset = srcAbs, srcMeta = srcAbs + ".meta", dstAsset = dstAbs, dstMeta = dstAbs + ".meta", isFolder = false }); } } else if (parts[1] == "ATLAS") { foreach (string assetPath in kvp.Value) { string srcAbs = AssetPathToAbs(assetPath); string fileName = Path.GetFileName(assetPath); string dstAbs = Path.Combine(absTargetFolder, fileName); if (NormalizePath(srcAbs).Equals(NormalizePath(dstAbs), StringComparison.OrdinalIgnoreCase)) continue; planned.Add(new PlannedMove { srcAsset = srcAbs, srcMeta = srcAbs + ".meta", dstAsset = dstAbs, dstMeta = dstAbs + ".meta", isFolder = false }); } } else if (parts[1] == "ATLAS_FOLDER") { foreach (string folderPath in kvp.Value) { string srcAbs = AssetPathToAbs(folderPath); string dstAbs = Path.Combine(absTargetFolder, newName); if (NormalizePath(srcAbs).Equals(NormalizePath(dstAbs), StringComparison.OrdinalIgnoreCase)) continue; planned.Add(new PlannedMove { srcAsset = srcAbs, srcMeta = srcAbs + ".meta", dstAsset = dstAbs, dstMeta = dstAbs + ".meta", isFolder = true }); } } continue; } string targetFolderPath2 = $"{parentFolder}/{folderType}"; string absTargetFolder2 = AssetPathToAbs(targetFolderPath2); if (!Directory.Exists(absTargetFolder2)) Directory.CreateDirectory(absTargetFolder2); foreach (string assetPath in kvp.Value) { string fileName = Path.GetFileName(assetPath); string baseName = Path.GetFileNameWithoutExtension(fileName); string ext = Path.GetExtension(fileName); string srcAbs = AssetPathToAbs(assetPath); string srcMeta = srcAbs + ".meta"; string dstName = fileName; string dstAbs = Path.Combine(absTargetFolder2, dstName); string dstMeta = dstAbs + ".meta"; int suffix = 1; while (usedNames.Contains(dstAbs) || (File.Exists(dstAbs) && !NormalizePath(srcAbs).Equals(NormalizePath(dstAbs), StringComparison.OrdinalIgnoreCase))) { dstName = $"{baseName}-{suffix.ToString("D2")}{ext}"; dstAbs = Path.Combine(absTargetFolder2, dstName); dstMeta = dstAbs + ".meta"; suffix++; } if (NormalizePath(srcAbs).Equals(NormalizePath(dstAbs), StringComparison.OrdinalIgnoreCase)) continue; usedNames.Add(dstAbs); planned.Add(new PlannedMove { srcAsset = srcAbs, srcMeta = srcMeta, dstAsset = dstAbs, dstMeta = dstMeta }); } } _plannedMoves = planned; } private static string AssetPathToAbs(string assetPath) { if (assetPath.StartsWith("Assets/")) return Path.Combine(Application.dataPath.Substring(0, Application.dataPath.Length - 6), assetPath); if (assetPath.StartsWith("Assets")) return Path.Combine(Application.dataPath.Substring(0, Application.dataPath.Length - 6), assetPath); return assetPath; } private void ProcessNextBatch() { if (!_isProcessing) { EditorApplication.update -= ProcessNextBatch; CleanupAfterProcessing(); return; } int batchSize = 10; int moved = 0; while (_plannedMoves.Count > 0 && moved < batchSize) { var move = _plannedMoves[0]; _plannedMoves.RemoveAt(0); if (move.isFolder) { if (!NormalizePath(move.srcAsset).Equals(NormalizePath(move.dstAsset), StringComparison.OrdinalIgnoreCase)) { if (Directory.Exists(move.dstAsset)) Directory.Delete(move.dstAsset, true); Directory.Move(move.srcAsset, move.dstAsset); } if (File.Exists(move.srcMeta) && !NormalizePath(move.srcMeta).Equals(NormalizePath(move.dstMeta), StringComparison.OrdinalIgnoreCase)) { if (File.Exists(move.dstMeta)) File.Delete(move.dstMeta); File.Move(move.srcMeta, move.dstMeta); } string folderType = Path.GetFileName(Path.GetDirectoryName(move.dstAsset)); if (!_organizedFolders.ContainsKey(folderType)) _organizedFolders[folderType] = 1; else _organizedFolders[folderType]++; } else { if (!NormalizePath(move.srcAsset).Equals(NormalizePath(move.dstAsset), StringComparison.OrdinalIgnoreCase)) { if (File.Exists(move.dstAsset)) File.Delete(move.dstAsset); if (File.Exists(move.srcAsset)) { File.Move(move.srcAsset, move.dstAsset); } else { _errorAssets.Add($"Source file not found: {move.srcAsset}"); moved++; continue; } } if (File.Exists(move.srcMeta) && !NormalizePath(move.srcMeta).Equals(NormalizePath(move.dstMeta), StringComparison.OrdinalIgnoreCase)) { if (File.Exists(move.dstMeta)) File.Delete(move.dstMeta); File.Move(move.srcMeta, move.dstMeta); } string folderType = Path.GetFileName(Path.GetDirectoryName(move.dstAsset)); if (!_organizedFolders.ContainsKey(folderType)) _organizedFolders[folderType] = 1; else _organizedFolders[folderType]++; } moved++; } _progress = 1f - (_plannedMoves.Count / (float)(1 + _plannedMoves.Count)); if (_plannedMoves.Count == 0) { int totalAssets = _organizedFolders.Values.Sum(); _reportTitle = totalAssets > 0 ? $"Successfully organized {totalAssets} assets into {_organizedFolders.Count} category folders!" : "No assets needed to be organized."; if (_errorAssets.Count > 0) { _reportTitle += $" Encountered {_errorAssets.Count} errors."; } EditorApplication.update -= ProcessNextBatch; AssetDatabase.Refresh(); CleanupAfterProcessing(); } _window.Repaint(); } private void DeleteEmptySubfolders(string parentFolder) { DeleteEmptyFoldersRecursive(parentFolder); } private static void DeleteEmptyFoldersRecursive(string root) { if (!Directory.Exists(root)) return; foreach (var dir in Directory.GetDirectories(root)) { var dirName = Path.GetFileName(dir); if (dirName.StartsWith(".")) continue; DeleteEmptyFoldersRecursive(dir.Replace("\\", "/")); if (IsUnityFolderEmptyStatic(dir.Replace("\\", "/"))) { string relPath = "Assets" + dir.Replace(Application.dataPath, "").Replace("\\", "/"); AssetDatabase.DeleteAsset(relPath); } } } private static bool IsUnityFolderEmptyStatic(string folder) { var files = Directory.GetFiles(folder); foreach (var file in files) { var fileName = Path.GetFileName(file); if (fileName == null) continue; if (fileName.StartsWith(".")) return false; if (!fileName.EndsWith(".meta", StringComparison.OrdinalIgnoreCase)) return false; } var dirs = Directory.GetDirectories(folder); foreach (var dir in dirs) { var dirName = Path.GetFileName(dir); if (dirName.StartsWith(".")) return false; if (!IsUnityFolderEmptyStatic(dir.Replace("\\", "/"))) return false; } return true; } private string GetAssetFolderType(string extension) { // Normalize extension to lowercase for case-insensitive comparison string normalizedExt = extension?.ToLowerInvariant() ?? ""; for (int i = 0; i < AssetFinderAssetGroupDrawer.FILTERS.Length - 1; i++) { AssetFinderAssetGroup filter = AssetFinderAssetGroupDrawer.FILTERS[i]; if (filter.extension.Contains(normalizedExt)) { return filter.name + "s"; } } return "Others"; } private class PlannedMove { public string srcAsset; public string srcMeta; public string dstAsset; public string dstMeta; public bool isFolder; } private class SpriteAtlasInfo { public string atlasPath; public List folders = new List(); public List sprites = new List(); } private class SpineAssetInfo { public string skeletonPath; public string spineName; public List assets = new List(); } private void CleanupEmptyMoveEntries() { var keysToRemove = new List(); foreach (var kvp in _assetsToMove) { if (kvp.Value.Count == 0) { keysToRemove.Add(kvp.Key); } } foreach (string key in keysToRemove) { _assetsToMove.Remove(key); } } private static string NormalizePath(string path) { return path.Replace('\\', '/').TrimEnd('/'); } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Drawer/AssetFinderAssetOrganizer.cs.meta ================================================ fileFormatVersion: 2 guid: 994fa27b9be091e499e68d19ffd1f368 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Drawer/AssetFinderBookmark.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using UnityEditor; using UnityEngine; using UnityObject = UnityEngine.Object; namespace VirtueSky.AssetFinder.Editor { internal class AssetFinderBookmark : IRefDraw { internal static readonly HashSet guidSet = new HashSet(); internal static readonly HashSet instSet = new HashSet(); // Do not reference directly to SceneObject (which might be destroyed anytime) // ------------ instance private static bool dirty; private readonly AssetFinderRefDrawer drawer; internal Dictionary refs = new Dictionary(); public AssetFinderBookmark(IWindow window, Func getSortMode, Func getGroupMode) { this.window = window; drawer = new AssetFinderRefDrawer(new AssetFinderRefDrawer.AssetDrawingConfig { window = window, getSortMode = getSortMode, getGroupMode = getGroupMode, showFullPath = false, showFileSize = false, showExtension = true, showUsageType = false, showAssetBundleName = false, showAtlasName = false, showToggle = true, showHighlight = false, shouldShowExtension = () => true, shouldShowDetailButton = () => true, onCacheInvalidated = () => { } // Bookmark panel manages its own state }) { messageNoRefs = "Do bookmark something!", groupDrawer = { hideGroupIfPossible = true }, level0Group = string.Empty, paddingLeft = -16f }; dirty = true; drawer.SetDirty(); } public static int Count => guidSet.Count + instSet.Count; public IWindow window { get; set; } public int ElementCount() { return refs == null ? 0 : refs.Count; } public bool DrawLayout() { if (dirty) RefreshView(); return drawer.DrawLayout(); } public bool Draw(Rect rect) { if (dirty) RefreshView(); if (refs == null) { AssetFinderLOG.LogWarning("Refs is null!"); return false; } var bottomRect = new Rect(rect.x + 1f, rect.yMax - 16f, rect.width - 2f, 16f); DrawButtons(bottomRect); rect.yMax -= 16f; return drawer.Draw(rect); } public static bool Contains(string guidOrInstID) { return guidSet.Contains(guidOrInstID) || instSet.Contains(guidOrInstID); } public static bool Contains(UnityObject sceneObject) { var id = sceneObject.GetInstanceID().ToString(); return instSet.Contains(id); } public static bool Contains(AssetFinderRef rf) { if (rf.isSceneRef) { if (instSet == null) return false; return instSet.Contains(rf.component.GetInstanceID().ToString()); } if (guidSet == null) return false; return guidSet.Contains(rf.asset.guid); } public static void Add(UnityObject sceneObject) { if (sceneObject == null) return; var id = sceneObject.GetInstanceID().ToString(); instSet.Add(id); dirty = true; } public static void Add(string guid) { if (guidSet.Contains(guid)) return; string assetPath = AssetDatabase.GUIDToAssetPath(guid); if (string.IsNullOrEmpty(assetPath)) { AssetFinderLOG.LogWarning("Invalid GUID: " + guid); return; } guidSet.Add(guid); dirty = true; } public static void Remove(UnityObject sceneObject) { if (sceneObject == null) return; var id = sceneObject.GetInstanceID().ToString(); instSet.Remove(id); dirty = true; } public static void Remove(string guidOrInstID) { guidSet.Remove(guidOrInstID); instSet.Remove(guidOrInstID); dirty = true; } public static void Clear() { guidSet.Clear(); instSet.Clear(); dirty = true; } public static void Add(AssetFinderRef rf) { if (rf.isSceneRef) { Add(rf.component); } else { Add(rf.asset.guid); } // Invalidate all drawer caches so group toggles update correctly InvalidateAllDrawerCaches(); } public static void Remove(AssetFinderRef rf) { if (rf.isSceneRef) //Debug.Log("remove: " + rf.component); { Remove(rf.component); } else { Remove(rf.asset.guid); } // Invalidate all drawer caches so group toggles update correctly InvalidateAllDrawerCaches(); } public static void Commit() { var list = new HashSet(); foreach (string guid in guidSet) { string path = AssetDatabase.GUIDToAssetPath(guid); UnityObject obj = AssetDatabase.LoadAssetAtPath(path, typeof(UnityObject)); if (obj != null) list.Add(obj); } foreach (string instID in instSet) { int id = int.Parse(instID); UnityObject obj = EditorUtility.InstanceIDToObject(id); if (obj == null) continue; list.Add(obj is Component c ? c.gameObject : obj); } Selection.objects = list.ToArray(); } public void SetDirty() { drawer.SetDirty(); } private void DrawButtons(Rect rect) { var (selectRect, exportRect) = rect.ExtractLeft(64f, 4f); GUI.enabled = (refs != null) && (refs.Count > 0); { if (GUI.Button(selectRect, AssetFinderGUIContent.FromString("Select", "Select items in Project or Hierarchy panel"))) Commit(); if (GUI.Button(exportRect, AssetFinderGUIContent.FromString("CSV", "Export bookmarked items as CSV"))) AssetFinderExport.ExportCSV(AssetFinderRef.FromDict(refs)); } GUI.enabled = true; // if (GUI.Button(right, AssetFinderIcon.Refresh.image)) RefreshView(); } public void RefreshView() { refs = new Dictionary(); //foreach (KeyValuePair> item in AssetFinderSetting.IgnoreFiltered) foreach (string guid in guidSet) { AssetFinderAsset asset = AssetFinderCache.Api.Get(guid, false); if (asset == null) { AssetFinderLOG.LogWarning("Invalid asset guid: " + guid); continue; } refs.Add(guid, new AssetFinderRef(0, 1, asset, null)); } foreach (string instID in instSet) { int id; if (!int.TryParse(instID, out id)) continue; var obj = EditorUtility.InstanceIDToObject(id); if (obj == null) continue; refs.Add(instID, new AssetFinderRef(0, 1, null, null) { component = obj, isSceneRef = true }); } drawer.SetRefs(refs); dirty = false; } internal void RefreshSort() { drawer.RefreshSort(); } // Callback for cache invalidation - set by AssetFinderWindowAll public static System.Action OnBookmarkChanged; private static void InvalidateAllDrawerCaches() { OnBookmarkChanged?.Invoke(); } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Drawer/AssetFinderBookmark.cs.meta ================================================ fileFormatVersion: 2 guid: 3ddd7baef5a53d048a4d84bd7fb20e35 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Drawer/AssetFinderDeleteEmptyFolder.cs ================================================ using System; using System.Collections.Generic; using System.IO; using System.Linq; using UnityEditor; using UnityEngine; using UnityObject = UnityEngine.Object; namespace VirtueSky.AssetFinder.Editor { internal class AssetFinderDeleteEmptyFolder : IRefDraw { private readonly IWindow _window; private bool _isProcessing; private float _progress; private List _foldersToDelete = new List(); private List _deletedFolders = new List(); private string _reportTitle; private int _currentIndex; internal AssetFinderDeleteEmptyFolder(IWindow window, Func getSort, Func getGroup) { _window = window; } public IWindow window => _window; public int ElementCount() => _deletedFolders.Count; public bool Draw(Rect rect) { GUI.BeginClip(rect); GUILayout.BeginArea(new Rect(0, 0, rect.width, rect.height)); bool result = DrawLayout(); GUILayout.EndArea(); GUI.EndClip(); return result; } public bool DrawLayout() { GUILayout.BeginVertical(); if (_isProcessing) { DrawProgressBar(); } else { if (GUILayout.Button("Delete All Empty Folders", AssetFinderTheme.Current.ActionButtonHeight)) { StartProcessing(); } if (!string.IsNullOrEmpty(_reportTitle)) { EditorGUILayout.HelpBox(_reportTitle, MessageType.Info); } if (_deletedFolders.Count > 0) { GUILayout.Space(10); EditorGUILayout.LabelField("Deleted Folders:", EditorStyles.boldLabel); GUILayout.BeginVertical(EditorStyles.helpBox); foreach (var folder in _deletedFolders.OrderBy(f => f)) { EditorGUILayout.LabelField(folder, EditorStyles.miniLabel); } GUILayout.EndVertical(); } } GUILayout.EndVertical(); GUILayout.FlexibleSpace(); return true; } private void DrawProgressBar() { EditorGUILayout.Space(); EditorGUILayout.LabelField("Deleting empty folders...", EditorStyles.boldLabel); Rect rect = AssetFinderTheme.Current.GetProgressBarRect(); EditorGUI.ProgressBar(rect, _progress, _currentIndex < _foldersToDelete.Count ? _foldersToDelete[_currentIndex] : "Done"); EditorGUILayout.Space(); if (GUILayout.Button("Cancel", AssetFinderTheme.Current.CancelButtonHeight)) { CancelProcessing(); } } private void StartProcessing() { _isProcessing = true; _progress = 0f; _foldersToDelete.Clear(); _deletedFolders.Clear(); _reportTitle = null; _currentIndex = 0; FindAllEmptyFolders("Assets"); _foldersToDelete = _foldersToDelete.Distinct().OrderByDescending(f => f.Length).ToList(); EditorApplication.update -= ProcessNextFolder; EditorApplication.update += ProcessNextFolder; } private void CancelProcessing() { _isProcessing = false; EditorApplication.update -= ProcessNextFolder; _window.Repaint(); } private void ProcessNextFolder() { if (!_isProcessing) { EditorApplication.update -= ProcessNextFolder; return; } if (_currentIndex >= _foldersToDelete.Count) { EditorApplication.update -= ProcessNextFolder; _isProcessing = false; GenerateReport(); _window.Repaint(); return; } string folder = _foldersToDelete[_currentIndex]; _progress = _currentIndex / (float)_foldersToDelete.Count; if (IsFolderEmpty(folder)) { AssetDatabase.DeleteAsset(folder); _deletedFolders.Add(folder); } _currentIndex++; _window.Repaint(); } private void FindAllEmptyFolders(string root) { foreach (var dir in Directory.GetDirectories(root)) { var dirName = Path.GetFileName(dir); if (dirName.StartsWith(".")) continue; // skip hidden folders FindAllEmptyFolders(dir.Replace("\\", "/")); if (IsUnityFolderEmpty(dir.Replace("\\", "/"))) { _foldersToDelete.Add(dir.Replace("\\", "/")); } } } private bool IsUnityFolderEmpty(string folder) { var files = Directory.GetFiles(folder); foreach (var file in files) { var fileName = Path.GetFileName(file); if (fileName == null) continue; if (fileName.StartsWith(".")) return false; // hidden file if (!fileName.EndsWith(".meta", StringComparison.OrdinalIgnoreCase)) return false; // any non-meta file } var dirs = Directory.GetDirectories(folder); foreach (var dir in dirs) { var dirName = Path.GetFileName(dir); if (dirName.StartsWith(".")) return false; // hidden subfolder if (!IsUnityFolderEmpty(dir.Replace("\\", "/"))) return false; } return true; } private bool IsFolderEmpty(string folder) { var files = Directory.GetFiles(folder).Where(f => !f.EndsWith(".meta")).ToArray(); var dirs = Directory.GetDirectories(folder); return files.Length == 0 && dirs.All(d => !AssetDatabase.IsValidFolder(d) || IsFolderEmpty(d.Replace("\\", "/"))); } private void GenerateReport() { if (_deletedFolders.Count > 0) { _reportTitle = $"Deleted {_deletedFolders.Count} empty folder(s)."; } else { _reportTitle = "No empty folders found."; } } // Public static method to delete all empty folders recursively from a root public static void DeleteAllEmptyFoldersRecursive(string root) { foreach (var dir in Directory.GetDirectories(root)) { var dirName = Path.GetFileName(dir); if (dirName.StartsWith(".")) continue; // skip hidden folders DeleteAllEmptyFoldersRecursive(dir.Replace("\\", "/")); if (IsUnityFolderEmptyStatic(dir.Replace("\\", "/"))) { string relPath = dir.Replace("\\", "/"); if (relPath.StartsWith(Application.dataPath)) { relPath = "Assets" + relPath.Substring(Application.dataPath.Length); } // Remove any double 'Assets' prefix while (relPath.StartsWith("AssetsAssets/")) { relPath = relPath.Substring("Assets".Length); } // Ensure single 'Assets/' at the start if (!relPath.StartsWith("Assets/")) { relPath = "Assets/" + relPath.TrimStart('/'); } // File IO delete: delete folder and .meta file string absPath = Path.Combine(Application.dataPath.Substring(0, Application.dataPath.Length - 6), relPath); // Remove 'Assets' from Application.dataPath if (Directory.Exists(absPath)) { Directory.Delete(absPath, true); } string metaPath = absPath + ".meta"; if (File.Exists(metaPath)) { File.Delete(metaPath); } } } } private static bool IsUnityFolderEmptyStatic(string folder) { var files = Directory.GetFiles(folder); foreach (var file in files) { var fileName = Path.GetFileName(file); if (fileName == null) continue; if (fileName.StartsWith(".")) return false; // hidden file if (!fileName.EndsWith(".meta", StringComparison.OrdinalIgnoreCase)) return false; // any non-meta file } var dirs = Directory.GetDirectories(folder); foreach (var dir in dirs) { var dirName = Path.GetFileName(dir); if (dirName.StartsWith(".")) return false; // hidden subfolder if (!IsUnityFolderEmptyStatic(dir.Replace("\\", "/"))) return false; } return true; } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Drawer/AssetFinderDeleteEmptyFolder.cs.meta ================================================ fileFormatVersion: 2 guid: f83f35cc96d96694c80d7bec055f99f8 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Drawer/AssetFinderIgnoreDrawer.cs ================================================ using System.Collections.Generic; using System.Linq; using UnityEditor; using UnityEngine; namespace VirtueSky.AssetFinder.Editor { internal class AssetFinderIgnoreDrawer { private readonly AssetFinderTreeUI2.GroupDrawer groupIgnore; private bool dirty; private Dictionary refs; public AssetFinderIgnoreDrawer() { groupIgnore = new AssetFinderTreeUI2.GroupDrawer(DrawGroup, DrawItem) { hideGroupIfPossible = true }; ApplyFiter(); } private void DrawItem(Rect r, string guid) { AssetFinderRef rf; if (!refs.TryGetValue(guid, out rf)) return; if (rf.depth == 1) //mode != Mode.Dependency && { Color c = GUI.color; GUI.color = Color.blue; GUI.DrawTexture(new Rect(r.x - 4f, r.y + 2f, 2f, 2f), EditorGUIUtility.whiteTexture); GUI.color = c; } rf.asset.Draw( r, new AssetFinderAsset.AssetFinderAssetDrawConfig( false, true, false, false, false, false, null, true ) ); Rect drawR = r; drawR.x = drawR.x + drawR.width - 50f; // (groupDrawer.TreeNoScroll() ? 60f : 70f) ; drawR.width = 30; drawR.y += 1; drawR.height -= 2; if (GUI.Button(drawR, "X", EditorStyles.miniButton)) AssetFinderSetting.RemoveIgnore(rf.asset.assetPath); } private void DrawGroup(Rect r, string id, int childCound) { GUI.Label(r, AssetFinderGUIContent.FromString(id), EditorStyles.boldLabel); if (childCound <= 1) return; Rect drawR = r; drawR.x = drawR.x + drawR.width - 50f; // (groupDrawer.TreeNoScroll() ? 60f : 70f) ; drawR.width = 30; drawR.y += 1; drawR.height -= 2; } public void SetDirty() { dirty = true; } //private float sizeRatio { // get{ // if(AssetFinderWindow.window != null) // return AssetFinderWindow.window.sizeRatio; // return .3f; // } //} public void Draw() { if (dirty) ApplyFiter(); GUILayout.BeginHorizontal(); { GUILayout.Space(4f); Object[] drops = GUI2.DropZone("Drag & Drop folders here to exclude", 100, 95); if ((drops != null) && (drops.Length > 0)) { for (var i = 0; i < drops.Length; i++) { string path = AssetDatabase.GetAssetPath(drops[i]); if (path.Equals(AssetFinderCache.DEFAULT_CACHE_PATH)) continue; AssetFinderSetting.AddIgnore(path); } } groupIgnore.DrawLayout(); } GUILayout.EndHorizontal(); } private void ApplyFiter() { dirty = false; refs = new Dictionary(); //foreach (KeyValuePair> item in AssetFinderSetting.IgnoreFiltered) foreach (string item2 in AssetFinderSetting.s.listIgnore) { string guid = AssetDatabase.AssetPathToGUID(item2); if (string.IsNullOrEmpty(guid)) continue; AssetFinderAsset asset = AssetFinderCache.Api.Get(guid, true); var r = new AssetFinderRef(0, 0, asset, null, "Ignore"); refs.Add(guid, r); } groupIgnore.Reset ( refs.Values.ToList(), rf => rf.asset != null ? rf.asset.guid : "", GetGroup, SortGroup ); } private string GetGroup(AssetFinderRef rf) { return "Ignore"; } private void SortGroup(List groups) { } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Drawer/AssetFinderIgnoreDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: dab80339cf5e1324f9ce59b4af29e79a MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Drawer/AssetFinderMissingReference.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using UnityEditor; using UnityEditor.SceneManagement; using UnityEngine; using UnityEngine.SceneManagement; using UnityObject = UnityEngine.Object; namespace VirtueSky.AssetFinder.Editor { internal class AssetFinderMissingReference : IRefDraw { // Processing state and dependencies private readonly IWindow _window; private bool _isProcessing; private float _progress; private string _currentAssetPath; private HashSet _processedAssets = new HashSet(); private List _assetsToProcess = new List(); // Results tracking private Dictionary _cleanedAssets = new Dictionary(); private List _errorAssets = new List(); private string _reportTitle; private StringBuilder _report = new StringBuilder(); // Scene handling private List _originalScenePaths = new List(); private Scene? _currentlyOpenScene = null; // Settings backup private AssetFinderAutoRefreshMode _originalAutoRefreshMode; internal AssetFinderMissingReference(IWindow window, Func getSort, Func getGroup) { _window = window; // Note: getSort and getGroup are unused but kept for interface compatibility } public IWindow window => _window; public int ElementCount() { return _cleanedAssets.Count + _errorAssets.Count; } public bool Draw(Rect rect) { GUI.BeginClip(rect); GUILayout.BeginArea(new Rect(0, 0, rect.width, rect.height)); bool result = DrawLayout(); GUILayout.EndArea(); GUI.EndClip(); return result; } public bool DrawLayout() { GUILayout.BeginVertical(); { if (_isProcessing) { DrawProgressBar(); } else { if (GUILayout.Button("Scan & Remove Missing Scripts", AssetFinderTheme.Current.ActionButtonHeight)) { StartProcessing(); } // Display report title if available if (!string.IsNullOrEmpty(_reportTitle)) EditorGUILayout.HelpBox(_reportTitle, MessageType.Info); // Show full report button if there are results if (_cleanedAssets.Count > 0 || _errorAssets.Count > 0) { if (GUILayout.Button("Full Report")) { AssetFinderLOG.Log(_report.ToString()); } } } } GUILayout.EndVertical(); GUILayout.FlexibleSpace(); return true; } private void DrawProgressBar() { EditorGUILayout.Space(); EditorGUILayout.LabelField("Processing assets...", EditorStyles.boldLabel); Rect rect = AssetFinderTheme.Current.GetProgressBarRect(); EditorGUI.ProgressBar(rect, _progress, $"Processing {_currentAssetPath} ({_processedAssets.Count}/{_assetsToProcess.Count})"); EditorGUILayout.Space(); if (GUILayout.Button("Cancel", AssetFinderTheme.Current.CancelButtonHeight)) { CancelProcessing(); } } private void StartProcessing() { try { DisableAutoRefresh(); SaveCurrentSceneSetup(); _isProcessing = true; _progress = 0f; _currentAssetPath = string.Empty; _processedAssets.Clear(); _assetsToProcess.Clear(); _cleanedAssets.Clear(); _errorAssets.Clear(); _report.Clear(); CollectAssetsToProcess(); SortAssetsByDependencyOrder(); EditorApplication.update -= ProcessNextAsset; EditorApplication.update += ProcessNextAsset; } catch (Exception ex) { AssetFinderLOG.LogError($"Error starting processing: {ex.Message}"); CleanupAfterProcessing(); } } private void CancelProcessing() { _isProcessing = false; CleanupAfterProcessing(); } private void CleanupAfterProcessing() { _isProcessing = false; RestoreOriginalScenes(); RestoreAutoRefreshMode(); _window.Repaint(); } private void ProcessNextAsset() { if (!_isProcessing) { EditorApplication.update -= ProcessNextAsset; CleanupAfterProcessing(); return; } if (_processedAssets.Count >= _assetsToProcess.Count) { EditorApplication.update -= ProcessNextAsset; GenerateReport(); CleanupAfterProcessing(); return; } string assetPath = _assetsToProcess[_processedAssets.Count]; _currentAssetPath = assetPath; _progress = _processedAssets.Count / (float)_assetsToProcess.Count; try { if (assetPath.EndsWith(".unity")) { ProcessScene(assetPath); } else if (assetPath.EndsWith(".prefab")) { ProcessPrefab(assetPath); } } catch (Exception ex) { AssetFinderLOG.LogError($"Error processing {assetPath}: {ex.Message}"); _errorAssets.Add(assetPath); } _processedAssets.Add(assetPath); _window.Repaint(); } private void DisableAutoRefresh() { _originalAutoRefreshMode = AssetFinderSettingExt.autoRefreshMode; AssetFinderSettingExt.autoRefreshMode = AssetFinderAutoRefreshMode.Off; } private void RestoreAutoRefreshMode() { AssetFinderSettingExt.autoRefreshMode = _originalAutoRefreshMode; } private void SaveCurrentSceneSetup() { _originalScenePaths.Clear(); for (int i = 0; i < SceneManager.sceneCount; i++) { Scene scene = SceneManager.GetSceneAt(i); if (!string.IsNullOrEmpty(scene.path)) { _originalScenePaths.Add(scene.path); } } } private void RestoreOriginalScenes() { try { _currentlyOpenScene = null; if (!EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo()) { return; } EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single); for (int i = 0; i < _originalScenePaths.Count; i++) { string scenePath = _originalScenePaths[i]; OpenSceneMode mode = i == 0 ? OpenSceneMode.Single : OpenSceneMode.Additive; EditorSceneManager.OpenScene(scenePath, mode); } } catch (Exception ex) { AssetFinderLOG.LogError($"Error restoring original scenes: {ex.Message}"); } } private void CollectAssetsToProcess() { AddAssetTypeToPipeline("t:Prefab"); AddAssetTypeToPipeline("t:Scene"); } private void AddAssetTypeToPipeline(string assetTypeFilter) { string[] guids = AssetDatabase.FindAssets(assetTypeFilter, new[] { "Assets" }); foreach (string guid in guids) { _assetsToProcess.Add(AssetDatabase.GUIDToAssetPath(guid)); } } private void SortAssetsByDependencyOrder() { Dictionary> dependencies = BuildDependencyGraph(out Dictionary> dependents); Dictionary assetLevels = CalculateAssetLevels(dependencies); _assetsToProcess = _assetsToProcess .OrderBy(path => assetLevels[path]) .ToList(); } private Dictionary> BuildDependencyGraph(out Dictionary> dependents) { Dictionary> dependencies = new Dictionary>(); dependents = new Dictionary>(); foreach (string assetPath in _assetsToProcess) { dependencies[assetPath] = new List(); dependents[assetPath] = new List(); } foreach (string assetPath in _assetsToProcess) { string[] dependencyPaths = AssetDatabase.GetDependencies(assetPath, false); foreach (string depPath in dependencyPaths) { if (_assetsToProcess.Contains(depPath) && depPath != assetPath) { dependencies[assetPath].Add(depPath); dependents[depPath].Add(assetPath); } } } return dependencies; } private Dictionary CalculateAssetLevels(Dictionary> dependencies) { Dictionary assetLevels = new Dictionary(); HashSet processed = new HashSet(); // First pass: assign level 0 to assets with no dependencies foreach (string assetPath in _assetsToProcess) { if (dependencies[assetPath].Count == 0) { assetLevels[assetPath] = 0; processed.Add(assetPath); } } // Process remaining assets bool changesMade = true; int currentLevel = 0; while (changesMade && processed.Count < _assetsToProcess.Count) { currentLevel++; changesMade = false; foreach (string assetPath in _assetsToProcess) { if (processed.Contains(assetPath)) continue; bool allDepsProcessed = true; foreach (string dep in dependencies[assetPath]) { if (!processed.Contains(dep)) { allDepsProcessed = false; break; } } if (allDepsProcessed) { assetLevels[assetPath] = currentLevel; processed.Add(assetPath); changesMade = true; } } } // Handle circular dependencies by assigning them to the next level if (processed.Count < _assetsToProcess.Count) { currentLevel++; foreach (string assetPath in _assetsToProcess) { if (!processed.Contains(assetPath)) { assetLevels[assetPath] = currentLevel; } } } return assetLevels; } private void GenerateReport() { _report.Clear(); int totalRemovedScripts = _cleanedAssets.Values.Sum(); if (_cleanedAssets.Count > 0) { _reportTitle = $"Removed missing scripts from {_cleanedAssets.Count} assets!"; _report.AppendLine($"Removed {totalRemovedScripts} missing script(s) from {_cleanedAssets.Count} assets:"); foreach (var asset in _cleanedAssets.OrderBy(x => x.Key)) { _report.AppendLine($"- {asset.Key}: {asset.Value} script(s) removed"); } _report.AppendLine(); } else { _reportTitle = "No missing scripts were found to remove."; _report.AppendLine("No missing scripts were found to remove."); _report.AppendLine(); } if (_errorAssets.Count > 0) { _report.AppendLine($"Errors occurred in {_errorAssets.Count} assets:"); foreach (string asset in _errorAssets.OrderBy(x => x)) { _report.AppendLine($"- {asset}"); } } } private void ProcessPrefab(string prefabPath) { try { GameObject prefabAsset = AssetDatabase.LoadAssetAtPath(prefabPath); if (prefabAsset == null) return; GameObject prefabInstance = PrefabUtility.InstantiatePrefab(prefabAsset) as GameObject; if (prefabInstance == null) return; try { int removedCount = RemoveMissingScriptsFromGameObject(prefabInstance); if (removedCount > 0) { PrefabUtility.ApplyPrefabInstance(prefabInstance, InteractionMode.AutomatedAction); _cleanedAssets[prefabPath] = removedCount; AssetDatabase.SaveAssets(); } } finally { UnityObject.DestroyImmediate(prefabInstance); } } catch (Exception ex) { AssetFinderLOG.LogError($"Error processing prefab {prefabPath}: {ex.Message}"); _errorAssets.Add(prefabPath); } } private void ProcessScene(string scenePath) { if (_currentlyOpenScene.HasValue && EditorSceneManager.GetActiveScene().isDirty) { EditorSceneManager.SaveScene(EditorSceneManager.GetActiveScene()); _currentlyOpenScene = null; } Scene scene = EditorSceneManager.OpenScene(scenePath, OpenSceneMode.Single); _currentlyOpenScene = scene; int removedCount = 0; foreach (GameObject rootObj in scene.GetRootGameObjects()) { removedCount += RemoveMissingScriptsFromGameObject(rootObj); } if (removedCount > 0) { EditorSceneManager.SaveScene(scene); _cleanedAssets[scenePath] = removedCount; } } private int RemoveMissingScriptsFromGameObject(GameObject gameObject) { int removedCount = 0; int missingCount = GameObjectUtility.GetMonoBehavioursWithMissingScriptCount(gameObject); if (missingCount > 0) { GameObjectUtility.RemoveMonoBehavioursWithMissingScript(gameObject); removedCount += missingCount; } foreach (Transform child in gameObject.transform) { removedCount += RemoveMissingScriptsFromGameObject(child.gameObject); } return removedCount; } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Drawer/AssetFinderMissingReference.cs.meta ================================================ fileFormatVersion: 2 guid: 5c3cf0d585651d34a80d39be086bc224 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Drawer/AssetFinderSetting.cs ================================================ using System; using System.Collections.Generic; using UnityEditor; using UnityEngine; using UnityEngine.Serialization; namespace VirtueSky.AssetFinder.Editor { [Serializable] internal class AssetFinderSetting { private static AssetFinderSetting d; [NonSerialized] private static HashSet _hashIgnore; // private static Dictionary> _IgnoreFiltered; public static Action OnIgnoreChange; public bool alternateColor = true; public int excludeTypes; //32-bit type Mask public List listIgnore = new List(); // public bool pingRow = true; public bool referenceCount = true; // public bool showPackageAsset = true; public bool showSubAssetFileId; public bool showFileSize; public bool displayFileSize = true; public bool displayAtlasName; public bool displayAssetBundleName; public bool showUsedByClassed = true; public int treeIndent = 10; public bool manualRefreshSelection; public Color32 rowColor = new Color32(0, 0, 0, 12); // public Color32 ScanColor = new Color32(0, 204, 102, 255); public Color SelectedColor = new Color(0, 0f, 1f, 0.25f); //public bool scanScripts = false; /* Doesn't have a settings option - I will include one in next update 2. Hide the reference number - Should be in the setting above so will be coming next 3. Cache file path should be configurable - coming next in the setting 4. Disable / Selectable color in alternative rows - coming next in the setting panel 5. Applied filters aren't saved - Should be fixed in next update too 6. Hide Selection part - should be com as an option so you can quickly toggle it on or off 7. Click whole line to ping - coming next by default and can adjustable in the setting panel */ internal static AssetFinderSetting s { get { if (AssetFinderCache.Api != null) return AssetFinderCache.Api.setting; if (d != null) return d; d = new AssetFinderSetting(); return d; } } public static bool ShowUsedByClassed => s.showUsedByClassed; public static bool ShowFileSize => s.showFileSize; public static int TreeIndent { get => s.treeIndent; set { if (s.treeIndent == value) return; s.treeIndent = value; setDirty(); } } public static bool ShowReferenceCount { get => s.referenceCount; set { if (s.referenceCount == value) return; s.referenceCount = value; setDirty(); } } public static bool AlternateRowColor { get => s.alternateColor; set { if (s.alternateColor == value) return; s.alternateColor = value; setDirty(); } } public static Color32 RowColor { get => s.rowColor; set { if (s.rowColor.Equals(value)) return; s.rowColor = value; setDirty(); } } // public static bool PingRow // { // get => s.pingRow; // set // { // if (s.pingRow == value) return; // // s.pingRow = value; // setDirty(); // } // } public static bool ManualRefreshSelection { get => s.manualRefreshSelection; set { if (s.manualRefreshSelection == value) return; s.manualRefreshSelection = value; setDirty(); } } public static HashSet IgnoreAsset { get { if (_hashIgnore != null) return _hashIgnore; _hashIgnore = new HashSet(); if (s?.listIgnore == null) return _hashIgnore; for (var i = 0; i < s.listIgnore.Count; i++) { _hashIgnore.Add(s.listIgnore[i]); } return _hashIgnore; } } // public static Dictionary> IgnoreFiltered // { // get // { // if (_IgnoreFiltered == null) // { // initIgnoreFiltered(); // } // // return _IgnoreFiltered; // } // } //static public bool ScanScripts //{ // get { return s.scanScripts; } // set { // if (s.scanScripts == value) return; // s.scanScripts = value; setDirty(); // } //} // public static AssetFinderRefDrawer.Mode GroupMode // { // get => s.groupMode; // set // { // if (s.groupMode.Equals(value)) return; // // s.groupMode = value; // setDirty(); // } // } // // public static AssetFinderRefDrawer.Sort SortMode // { // get => s.sortMode; // set // { // if (s.sortMode.Equals(value)) return; // // s.sortMode = value; // setDirty(); // } // } public static bool HasTypeExcluded => s.excludeTypes != 0; private static void setDirty() { if (AssetFinderCache.Api != null) EditorUtility.SetDirty(AssetFinderCache.Api); } // private static void initIgnoreFiltered() // { // AssetFinderAsset.ignoreTS = Time.realtimeSinceStartup; // // _IgnoreFiltered = new Dictionary>(); // var lst = new List(s.listIgnore); // lst = lst.OrderBy(x => x.Length).ToList(); // int count = lst.Count; // for (var i = 0; i < count; i++) // { // string str = lst[i]; // _IgnoreFiltered.Add(str, new List {str}); // for (int j = count - 1; j > i; j--) // { // if (lst[j].StartsWith(str)) // { // _IgnoreFiltered[str].Add(lst[j]); // lst.RemoveAt(j); // count--; // } // } // } // } public static void AddIgnore(string path) { if (string.IsNullOrEmpty(path) || IgnoreAsset.Contains(path) || path == "Assets") return; s.listIgnore.Add(path); _hashIgnore.Add(path); AssetFinderAssetGroupDrawer.SetDirtyIgnore(); AssetFinderCacheHelper.InitIgnore(); //initIgnoreFiltered(); AssetFinderAsset.ignoreTS = Time.realtimeSinceStartup; if (OnIgnoreChange != null) OnIgnoreChange(); } public static void RemoveIgnore(string path) { if (!IgnoreAsset.Contains(path)) return; _hashIgnore.Remove(path); s.listIgnore.Remove(path); AssetFinderAssetGroupDrawer.SetDirtyIgnore(); AssetFinderCacheHelper.InitIgnore(); //initIgnoreFiltered(); AssetFinderAsset.ignoreTS = Time.realtimeSinceStartup; if (OnIgnoreChange != null) OnIgnoreChange(); } public static bool IsTypeExcluded(int type) { return ((s.excludeTypes >> type) & 1) != 0; } public static void ToggleTypeExclude(int type) { bool v = ((s.excludeTypes >> type) & 1) != 0; if (v) { s.excludeTypes &= ~(1 << type); } else { s.excludeTypes |= 1 << type; } setDirty(); } public static int GetExcludeType() { return s.excludeTypes; } public static bool IsIncludeAllType() { // Debug.Log ((AssetType.FILTERS.Length & s.excludeTypes) + " " + Mathf.Pow(2, AssetType.FILTERS.Length) ); return s.excludeTypes == 0 || Mathf.Abs(s.excludeTypes) == Mathf.Pow(2, AssetFinderAssetGroupDrawer.FILTERS.Length); } public static void ExcludeAllType() { s.excludeTypes = -1; } public static void IncludeAllType() { s.excludeTypes = 0; } public void DrawSettings() { EditorGUI.BeginChangeCheck(); { s.alternateColor = EditorGUILayout.Toggle("Alternate Row Color", s.alternateColor); s.showUsedByClassed = EditorGUILayout.Toggle("Show Usage Icon", s.showUsedByClassed); // s.pingRow = EditorGUILayout.Toggle("Ping Row", s.pingRow); s.referenceCount = EditorGUILayout.Toggle("Reference Count", s.referenceCount); // s.showPackageAsset = EditorGUILayout.Toggle("Show Package Assets", s.showPackageAsset); // s.showSubAssetFileId = EditorGUILayout.Toggle("Show Sub Asset File ID", s.showSubAssetFileId); // s.showFileSize = EditorGUILayout.Toggle("Show File Size", s.showFileSize); } if (EditorGUI.EndChangeCheck()) { setDirty(); } } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Drawer/AssetFinderSetting.cs.meta ================================================ fileFormatVersion: 2 guid: 84c3e9e57209fbc45b591d007e25f316 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Drawer/AssetFinderUsedInBuild.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using UnityEditor; using UnityEngine; namespace VirtueSky.AssetFinder.Editor { internal class AssetFinderUsedInBuild : IRefDraw { private readonly AssetFinderRefDrawer drawer; private readonly AssetFinderTreeUI2.GroupDrawer groupDrawer; private bool dirty; internal Dictionary refs; public AssetFinderUsedInBuild(IWindow window, Func getSortMode, Func getGroupMode) { this.window = window; drawer = new AssetFinderRefDrawer(new AssetFinderRefDrawer.AssetDrawingConfig { window = window, getSortMode = getSortMode, getGroupMode = getGroupMode, showFullPath = false, showFileSize = true, showExtension = true, showUsageType = false, showAssetBundleName = false, showAtlasName = false }) { messageNoRefs = "No scene enabled in Build Settings!" }; dirty = true; drawer.SetDirty(); } public IWindow window { get; set; } // Expose internal drawer for display property access public AssetFinderRefDrawer Drawer => drawer; public int ElementCount() { return refs?.Count ?? 0; } public bool Draw(Rect rect) { if (dirty) RefreshView(); return drawer.Draw(rect); } public bool DrawLayout() { if (dirty) RefreshView(); return drawer.DrawLayout(); } public void SetDirty() { dirty = true; drawer.SetDirty(); } public void RefreshView() { var scenes = new HashSet(); foreach (EditorBuildSettingsScene scene in EditorBuildSettings.scenes) { if (scene == null) continue; if (scene.enabled == false) continue; string sce = AssetDatabase.AssetPathToGUID(scene.path); if (scenes.Contains(sce)) continue; scenes.Add(sce); } refs = new Dictionary(); Dictionary directRefs = AssetFinderRef.FindUsage(scenes.ToArray()); foreach (string scene in scenes) { if (!directRefs.TryGetValue(scene, out AssetFinderRef asset)) continue; asset.depth = 1; } List list = AssetFinderCache.Api.AssetList; int count = list.Count; // Collect assets in Resources / Streaming Assets for (var i = 0; i < count; i++) { AssetFinderAsset item = list[i]; if (item.inEditor) continue; if (item.IsExcluded) continue; if (item.IsFolder) continue; if (!item.assetPath.StartsWith("Assets/", StringComparison.Ordinal)) continue; if (item.inResources || item.inStreamingAsset || item.inPlugins || item.forcedIncludedInBuild || !string.IsNullOrEmpty(item.AssetBundleName) || !string.IsNullOrEmpty(item.AtlasName)) { if (refs.ContainsKey(item.guid)) continue; refs.Add(item.guid, new AssetFinderRef(0, 1, item, null)); } } // Collect direct references foreach (KeyValuePair kvp in directRefs) { AssetFinderAsset item = kvp.Value.asset; if (item.inEditor) continue; if (item.IsExcluded) continue; if (!item.assetPath.StartsWith("Assets/", StringComparison.Ordinal)) continue; if (refs.ContainsKey(item.guid)) continue; refs.Add(item.guid, new AssetFinderRef(0, 1, item, null)); } drawer.SetRefs(refs); dirty = false; } internal void RefreshSort() { drawer.RefreshSort(); } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Drawer/AssetFinderUsedInBuild.cs.meta ================================================ fileFormatVersion: 2 guid: 6480768d52898e346865d2e94ba43ffd MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Drawer.meta ================================================ fileFormatVersion: 2 guid: b8dc12b3e4ad4bb8ac5cea3451bbc66f timeCreated: 1746365376 ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Duplicate/AssetFinderChunk.cs ================================================ using System.IO; namespace VirtueSky.AssetFinder.Editor { internal class AssetFinderChunk { public byte[] buffer; public string file; public long size; public FileStream stream; public bool streamError; public bool streamInited; } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Duplicate/AssetFinderChunk.cs.meta ================================================ fileFormatVersion: 2 guid: bbaa77776ba63e24bbc227ec3072fc43 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Duplicate/AssetFinderDuplicateTree2.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using UnityEditor; using UnityEngine; using Object = UnityEngine.Object; namespace VirtueSky.AssetFinder.Editor { internal class AssetFinderDuplicateTree2 : IRefDraw { private const float TimeDelayDelete = .5f; private static readonly AssetFinderFileCompare fc = new AssetFinderFileCompare(); private readonly Func getGroupMode; private readonly Func getSortMode; private readonly AssetFinderTreeUI2.GroupDrawer groupDrawer; private readonly string searchTerm = ""; private List> cacheAssetList; public bool caseSensitive = false; private Dictionary> dicIndex; //index, list private bool dirty; private int excludeCount; private string guidPressDelete; internal List list; internal Dictionary refs; public int scanExcludeByIgnoreCount; public int scanExcludeByTypeCount; private float TimePressDelete; // New fields for verification UI private Dictionary groupVerificationStatus = new Dictionary(); private Dictionary groupVerificationProgress = new Dictionary(); private Dictionary groupVerificationOrder = new Dictionary(); private bool isSignatureScanComplete = false; // Add enum for progress state private enum ProgressState { Idle, Scanning, Verifying, Complete } private ProgressState progressState = ProgressState.Idle; public AssetFinderDuplicateTree2(IWindow window, Func getSortMode, Func getGroupMode) { this.window = window; this.getSortMode = getSortMode; this.getGroupMode = getGroupMode; groupDrawer = new AssetFinderTreeUI2.GroupDrawer(DrawGroup, DrawAsset); } public IWindow window { get; set; } public bool Draw(Rect rect) { return false; } public bool DrawLayout() { if (dirty) RefreshView(cacheAssetList); // Show progress bar on top based on progressState if (progressState == ProgressState.Scanning || progressState == ProgressState.Verifying) { float p = fc.nScaned / (float)Mathf.Max(1, fc.nChunks2); string label = progressState == ProgressState.Scanning ? "Scanning" : "Verifying"; Rect progressRect = GUILayoutUtility.GetRect(1, Screen.width, 18f, 18f); EditorGUI.ProgressBar(progressRect, p, string.Format($"{label} {{0}} / {{1}}", fc.nScaned, fc.nChunks2)); GUILayout.Space(2); } // Update progress state based on fc if (fc.nChunks2 > 0 && fc.nScaned < fc.nChunks2) { if (progressState != ProgressState.Scanning && progressState != ProgressState.Verifying) progressState = ProgressState.Scanning; } else if (fc.nChunks2 > 0 && fc.nScaned >= fc.nChunks2) { if (progressState != ProgressState.Complete) progressState = ProgressState.Complete; } else { progressState = ProgressState.Idle; } if (progressState == ProgressState.Complete || progressState == ProgressState.Idle) { if (groupDrawer.hasValidTree) groupDrawer.tree.itemPaddingRight = 60f; groupDrawer.DrawLayout(); } DrawHeader(); return false; } public int ElementCount() { return list?.Count ?? 0; } private void DrawAsset(Rect r, string guid) { if (!refs.TryGetValue(guid, out AssetFinderRef rf)) return; var assetRect = r; assetRect.width -= 70f; rf.asset.Draw( assetRect, new AssetFinderAsset.AssetFinderAssetDrawConfig( false, getGroupMode() != AssetFinderRefDrawer.Mode.Folder, AssetFinderSetting.ShowFileSize, AssetFinderSetting.s.displayAssetBundleName, AssetFinderSetting.s.displayAtlasName, AssetFinderSetting.s.showUsedByClassed, window, true ) ); Texture tex = AssetDatabase.GetCachedIcon(rf.asset.assetPath); if (tex == null) return; Rect drawR = r; drawR.x += drawR.width; // (groupDrawer.TreeNoScroll() ? 60f : 70f) ; drawR.width = 40f; drawR.y += 1; drawR.height -= 2; if (GUI.Button(drawR, "Use", EditorStyles.miniButton)) { if (AssetFinderExport.IsMergeProcessing) { AssetFinderLOG.LogWarning("Previous merge is processing"); } else { int index = rf.index; Selection.objects = list.Where(x => x.index == index) .Select(x => AssetFinderUnity.LoadAssetAtPath(x.asset.assetPath)).ToArray(); AssetFinderExport.MergeDuplicate(rf.asset.guid); } } if (rf.asset.UsageCount() > 0) return; drawR.x -= 25; drawR.width = 20; if (wasPreDelete(guid)) { Color col = GUI.color; GUI.color = Color.red; if (GUI.Button(drawR, "X", EditorStyles.miniButton)) { guidPressDelete = null; AssetDatabase.DeleteAsset(rf.asset.assetPath); } GUI.color = col; window.WillRepaint = true; } else { if (GUI.Button(drawR, "X", EditorStyles.miniButton)) { guidPressDelete = guid; TimePressDelete = Time.realtimeSinceStartup; window.WillRepaint = true; } } } private bool wasPreDelete(string guid) { if (guidPressDelete == null || guid != guidPressDelete) return false; if (Time.realtimeSinceStartup - TimePressDelete < TimeDelayDelete) return true; guidPressDelete = null; return false; } private void DrawGroup(Rect r, string label, int childCount) { AssetFinderAsset asset = dicIndex[label][0].asset; Texture tex = AssetDatabase.GetCachedIcon(asset.assetPath); Rect rect = r; if (tex != null) { rect.width = 16f; GUI.DrawTexture(rect, tex); } rect = r; rect.xMin += 16f; GUI.Label(rect, asset.assetName, EditorStyles.boldLabel); rect = r; rect.xMin += rect.width - 50f; GUI.Label(rect, AssetFinderHelper.GetfileSizeString(asset.fileSize), EditorStyles.miniLabel); rect = r; rect.xMin += rect.width - 100f; GUI.Label(rect, childCount.ToString(), EditorStyles.miniLabel); // Removed: status/progress/queue UI } public void Reset(List> assetList) { progressState = ProgressState.Scanning; groupVerificationStatus.Clear(); groupVerificationProgress.Clear(); groupVerificationOrder.Clear(); fc.Reset(assetList, OnUpdateView, RefreshView); } private void OnUpdateView(List> assetList) { // This is called during verification to update the view with current results if (assetList != null) { cacheAssetList = assetList; dirty = true; window.WillRepaint = true; } } public bool isExclueAnyItem() { return excludeCount > 0 || scanExcludeByTypeCount > 0; } public bool isExclueAnyItemByIgnoreFolder() { return scanExcludeByIgnoreCount > 0; } private void RefreshView(List> assetList) { cacheAssetList = assetList; dirty = false; list = new List(); refs = new Dictionary(); dicIndex = new Dictionary>(); if (assetList == null) return; int minScore = searchTerm.Length; string term1 = searchTerm; if (!caseSensitive) term1 = term1.ToLower(); string term2 = term1.Replace(" ", string.Empty); excludeCount = 0; for (var i = 0; i < assetList.Count; i++) { var lst = new List(); for (var j = 0; j < assetList[i].Count; j++) { string path = assetList[i][j]; if (!path.StartsWith("Assets/")) { AssetFinderLOG.LogWarning("Ignore asset: " + path); continue; } string guid = AssetDatabase.AssetPathToGUID(path); if (string.IsNullOrEmpty(guid)) continue; if (refs.ContainsKey(guid)) continue; AssetFinderAsset asset = AssetFinderCache.Api.Get(guid); if (asset == null) continue; if (!asset.assetPath.StartsWith("Assets/")) continue; // ignore builtin, packages, ... var fr2 = new AssetFinderRef(i, 0, asset, null); if (AssetFinderSetting.IsTypeExcluded(fr2.type)) { excludeCount++; continue; //skip this one } if (string.IsNullOrEmpty(searchTerm)) { fr2.matchingScore = 0; list.Add(fr2); lst.Add(fr2); refs.Add(guid, fr2); continue; } //calculate matching score string name1 = fr2.asset.assetName; if (!caseSensitive) name1 = name1.ToLower(); string name2 = name1.Replace(" ", string.Empty); int score1 = AssetFinderUnity.StringMatch(term1, name1); int score2 = AssetFinderUnity.StringMatch(term2, name2); fr2.matchingScore = Mathf.Max(score1, score2); if (fr2.matchingScore > minScore) { list.Add(fr2); lst.Add(fr2); refs.Add(guid, fr2); } } dicIndex.Add(i.ToString(), lst); // Initialize verification status for the group if (isSignatureScanComplete) { groupVerificationStatus[i.ToString()] = "Pending"; } } ResetGroup(); } private void ResetGroup() { groupDrawer.Reset(list, rf => rf.asset.guid , GetGroup, SortGroup); if (window != null) window.Repaint(); } private string GetGroup(AssetFinderRef rf) { return rf.index.ToString(); } private void SortGroup(List groups) { // Sort by verification status, then by size if (isSignatureScanComplete) { groups.Sort((a, b) => { // First check if either is currently verifying if (groupVerificationStatus.ContainsKey(a) && groupVerificationStatus[a] == "Verifying") return -1; if (groupVerificationStatus.ContainsKey(b) && groupVerificationStatus[b] == "Verifying") return 1; // Then check if verified bool aVerified = groupVerificationStatus.ContainsKey(a) && groupVerificationStatus[a] == "Verified"; bool bVerified = groupVerificationStatus.ContainsKey(b) && groupVerificationStatus[b] == "Verified"; if (aVerified && !bVerified) return -1; if (!aVerified && bVerified) return 1; // Then check queue position if (groupVerificationOrder.ContainsKey(a) && groupVerificationOrder.ContainsKey(b)) return groupVerificationOrder[a].CompareTo(groupVerificationOrder[b]); // Default to standard order return a.CompareTo(b); }); } } public void SetDirty() { dirty = true; } public void RefreshSort() { if (groupDrawer.hasValidTree) { SortGroup(groupDrawer.tree.rootItem.children.Select(item => item.id).ToList()); groupDrawer.Reset(list, rf => rf.asset.guid, GetGroup, SortGroup); if (window != null) window.Repaint(); } } private void DrawHeader() { string text = groupDrawer.hasValidTree ? "Rescan" : "Scan"; EditorGUILayout.BeginHorizontal(); if (GUILayout.Button(text)) { OnCacheReady(); } // Removed: Refresh Sort button EditorGUILayout.EndHorizontal(); // Removed: bottom status text } private void OnCacheReady() { scanExcludeByTypeCount = 0; Reset(AssetFinderCache.Api.ScanSimilar(IgnoreTypeWhenScan, IgnoreFolderWhenScan)); AssetFinderCache.onReady -= OnCacheReady; } private void IgnoreTypeWhenScan() { scanExcludeByTypeCount++; } private void IgnoreFolderWhenScan() { scanExcludeByIgnoreCount++; } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Duplicate/AssetFinderDuplicateTree2.cs.meta ================================================ fileFormatVersion: 2 guid: f858ea142423a864caf1f7888f216d13 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Duplicate/AssetFinderFileCompare.cs ================================================ using System; using System.Collections.Generic; using System.IO; using System.Linq; using UnityEditor; using UnityEngine; namespace VirtueSky.AssetFinder.Editor { internal class AssetFinderFileCompare { public static HashSet HashChunksNotComplete; internal static int streamClosedCount; private List> cacheList; public List deads = new List(); public List heads = new List(); public int nChunks; public int nChunks2; public int nScaned; public Action>> OnCompareComplete; public Action>> OnCompareUpdate; // Verification tracking private Dictionary verificationProgress = new Dictionary(); private Dictionary verificationOrder = new Dictionary(); private Queue verificationQueue = new Queue(); private string currentlyVerifying = null; private bool signatureScanComplete = false; public void Reset(List> list, Action>> onUpdate, Action>> onComplete) { nChunks = 0; nScaned = 0; nChunks2 = 0; HashChunksNotComplete = new HashSet(); if (heads.Count > 0) { for (var i = 0; i < heads.Count; i++) { heads[i].CloseChunk(); } } deads.Clear(); heads.Clear(); verificationProgress.Clear(); verificationOrder.Clear(); verificationQueue.Clear(); currentlyVerifying = null; signatureScanComplete = true; // Since we're using fileInfoHash, signatures are already computed OnCompareUpdate = onUpdate; OnCompareComplete = onComplete; if (list == null || list.Count <= 0) { OnCompareComplete(new List>()); return; } cacheList = list; // Sort groups by file size (smallest first for quicker processing) cacheList.Sort((a, b) => { long sizeA = new FileInfo(a[0]).Length; long sizeB = new FileInfo(b[0]).Length; return sizeA.CompareTo(sizeB); }); // Setup verification queue PrepareVerificationQueue(); } private void PrepareVerificationQueue() { // Create verification queue for (int i = 0; i < cacheList.Count; i++) { string groupKey = "Group-" + i; verificationQueue.Enqueue(groupKey); verificationOrder[groupKey] = i + 1; verificationProgress[groupKey] = 0f; } // Trigger initial update with hash-based results OnCompareUpdate?.Invoke(cacheList); // Start verification if (verificationQueue.Count > 0) { StartNextVerification(); } else { OnCompareComplete?.Invoke(new List>()); } } private void StartNextVerification() { if (verificationQueue.Count > 0) { currentlyVerifying = verificationQueue.Dequeue(); // Use existing byte-by-byte verification AddHead(cacheList[cacheList.Count - 1]); cacheList.RemoveAt(cacheList.Count - 1); EditorApplication.update -= ReadChunkAsync; EditorApplication.update += ReadChunkAsync; } else { // All verifications complete currentlyVerifying = null; OnCompareComplete?.Invoke(deads.Select(item => item.GetFiles()).ToList()); } } public void PrioritizeGroup(string groupKey) { if (verificationQueue.Contains(groupKey)) { // Remove from the queue List newQueue = verificationQueue.Where(k => k != groupKey).ToList(); verificationQueue.Clear(); // Add the prioritized group at the front verificationQueue.Enqueue(groupKey); // Add the rest back foreach (string key in newQueue) { verificationQueue.Enqueue(key); } // Update order numbers int position = 1; foreach (string key in verificationQueue) { verificationOrder[key] = position++; } } } public Dictionary GetVerificationProgress() { return verificationProgress; } public Dictionary GetVerificationOrder() { return verificationOrder; } public string GetCurrentlyVerifying() { return currentlyVerifying; } public bool IsSignatureScanComplete() { return signatureScanComplete; } public AssetFinderFileCompare AddHead(List files) { if (files.Count < 2) Debug.LogWarning("Something wrong ! head should not contains < 2 elements"); var chunkList = new List(); for (var i = 0; i < files.Count; i++) { chunkList.Add(new AssetFinderChunk { file = files[i], buffer = new byte[AssetFinderHead.chunkSize] }); } var file = new FileInfo(files[0]); int nChunk = Mathf.CeilToInt(file.Length / (float)AssetFinderHead.chunkSize); heads.Add(new AssetFinderHead { fileSize = file.Length, currentChunk = 0, nChunk = nChunk, chunkList = chunkList, groupKey = currentlyVerifying }); nChunks += nChunk; return this; } private void ReadChunkAsync() { bool alive = ReadChunk(); if (alive) { // Update verification progress if (currentlyVerifying != null && nChunks > 0) { verificationProgress[currentlyVerifying] = (float)nScaned / nChunks; } return; } var update = false; for (int i = heads.Count - 1; i >= 0; i--) { AssetFinderHead h = heads[i]; if (!h.isDead) continue; h.CloseChunk(); heads.RemoveAt(i); if (h.chunkList.Count > 1) { update = true; deads.Add(h); } } if (update) Trigger(OnCompareUpdate); // Set verification as complete for current group if (currentlyVerifying != null) { verificationProgress[currentlyVerifying] = 1f; } if (cacheList.Count == 0) { foreach (AssetFinderChunk item in HashChunksNotComplete) { if (item.stream == null || !item.stream.CanRead) continue; item.stream.Close(); item.stream = null; } HashChunksNotComplete.Clear(); nScaned = nChunks; EditorApplication.update -= ReadChunkAsync; // Verification complete, final callback Trigger(OnCompareComplete); } else { // Continue with next group StartNextVerification(); } } private void Trigger(Action>> cb) { if (cb == null) return; List> list = deads.Select(item => item.GetFiles()).ToList(); cb(list); } private bool ReadChunk() { var alive = false; for (var i = 0; i < heads.Count; i++) { AssetFinderHead h = heads[i]; if (h.isDead) { continue; } nScaned++; alive = true; h.ReadChunk(); h.CompareChunk(heads); break; } return alive; } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Duplicate/AssetFinderFileCompare.cs.meta ================================================ fileFormatVersion: 2 guid: 1fcea19945e771a46ad57540490f9275 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Duplicate/AssetFinderHead.cs ================================================ using System; using System.Collections.Generic; using System.IO; using System.Linq; using UnityEngine; namespace VirtueSky.AssetFinder.Editor { internal class AssetFinderHead { public const int chunkSize = 10240; public List chunkList; public int currentChunk; public long fileSize; public int nChunk; public int size; //last stream read size public string groupKey; // For tracking group identity in verification queue public bool isDead => currentChunk == nChunk || chunkList.Count == 1; public List GetFiles() { return chunkList.Select(item => item.file).ToList(); } public void AddToDict(byte b, AssetFinderChunk chunk, Dictionary> dict) { List list; if (!dict.TryGetValue(b, out list)) { list = new List(); dict.Add(b, list); } list.Add(chunk); } public void CloseChunk() { for (var i = 0; i < chunkList.Count; i++) { AssetFinderFileCompare.streamClosedCount++; if (chunkList[i].stream != null) { chunkList[i].stream.Close(); chunkList[i].stream = null; } } } public void ReadChunk() { if (currentChunk == nChunk) { AssetFinderLOG.LogWarning("Something wrong, should dead <" + isDead + ">"); return; } int from = currentChunk * chunkSize; size = (int)Mathf.Min(fileSize - from, chunkSize); for (var i = 0; i < chunkList.Count; i++) { AssetFinderChunk chunk = chunkList[i]; if (chunk.streamError) continue; chunk.size = size; if (chunk.streamInited == false) { chunk.streamInited = true; try { chunk.stream = new FileStream(chunk.file, FileMode.Open, FileAccess.Read); } catch { chunk.streamError = true; if (chunk.stream != null) // just to make sure we close the stream { chunk.stream.Close(); chunk.stream = null; } } if (chunk.stream == null) { chunk.streamError = true; continue; } } try { chunk.stream.Seek(from, SeekOrigin.Begin); chunk.stream.Read(chunk.buffer, 0, size); } catch (Exception e) { AssetFinderLOG.LogWarning(e + "\n" + chunk.file); chunk.streamError = true; chunk.stream.Close(); } } // clean up dead chunks for (int i = chunkList.Count - 1; i >= 0; i--) { if (chunkList[i].streamError) chunkList.RemoveAt(i); } if (chunkList.Count == 1) Debug.LogWarning("No more chunk in list"); currentChunk++; } public void CompareChunk(List heads) { int idx = chunkList.Count; byte[] buffer = chunkList[idx - 1].buffer; while (--idx >= 0) { AssetFinderChunk chunk = chunkList[idx]; int diff = FirstDifferentIndex(buffer, chunk.buffer, size); if (diff == -1) continue; byte v = buffer[diff]; var d = new Dictionary>(); //new heads chunkList.RemoveAt(idx); AssetFinderFileCompare.HashChunksNotComplete.Add(chunk); AddToDict(chunk.buffer[diff], chunk, d); for (int j = idx - 1; j >= 0; j--) { AssetFinderChunk tChunk = chunkList[j]; byte tValue = tChunk.buffer[diff]; if (tValue == v) continue; idx--; AssetFinderFileCompare.HashChunksNotComplete.Add(tChunk); chunkList.RemoveAt(j); AddToDict(tChunk.buffer[diff], tChunk, d); } foreach (KeyValuePair> item in d) { List list = item.Value; if (list.Count == 1) { if (list[0].stream != null) list[0].stream.Close(); } else if (list.Count > 1) // 1 : dead head { heads.Add(new AssetFinderHead { nChunk = nChunk, fileSize = fileSize, currentChunk = currentChunk - 1, chunkList = list, groupKey = groupKey // Propagate the groupKey to new heads }); } } } } internal static int FirstDifferentIndex(byte[] arr1, byte[] arr2, int maxIndex) { for (var i = 0; i < maxIndex; i++) { if (arr1[i] != arr2[i]) return i; } return -1; } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Duplicate/AssetFinderHead.cs.meta ================================================ fileFormatVersion: 2 guid: 2bfaaba7291e7244d984c18caaa91464 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Duplicate.meta ================================================ fileFormatVersion: 2 guid: b5e941cf0fab44ba90c39a055cd2602e timeCreated: 1747080908 ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Extension/AssetFinderExtension.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using UnityEditor; using UnityEngine; namespace VirtueSky.AssetFinder.Editor { internal static class GUIExtension { internal static bool drawDebug = false; internal static readonly float debugAlpha = 0.02f; internal static int debugCount; internal static readonly Color[] debugColors = { Color.cyan.Alpha(debugAlpha), Color.blue.Alpha(debugAlpha), Color.green.Alpha(debugAlpha), Color.yellow.Alpha(debugAlpha), Color.magenta.Alpha(debugAlpha), Color.red.Alpha(debugAlpha), Color.white.Alpha(debugAlpha) }; #if AssetFinderDEV [MenuItem("Window/FR2/Toggle Draw Debug")] internal static void ToggleDrawDebug() { drawDebug = !drawDebug; } #endif internal static bool isRepaint => Event.current.type == EventType.Repaint; internal static bool isMouse => Event.current.isMouse; internal static bool isLayout => Event.current.type == EventType.Layout; public static Rect DrawOverlayDebug(this Rect rect, float alpha = 0.1f) { Color saved = GUI.color; GUI.color = debugColors[debugCount++ % debugColors.Length]; { GUI.DrawTexture(rect, Texture2D.whiteTexture, ScaleMode.StretchToFill); } GUI.color = saved; return rect; } public static Rect LFoldout(this Rect rect, ref bool isOpen, bool drawCondition) { var (iconRect, flexRect) = rect.ExtractLeft(); if (!drawCondition) return flexRect; isOpen = EditorGUI.Foldout(iconRect, isOpen, GUIContent.none); if (drawDebug) DrawOverlayDebug(iconRect.Move(0, -2f)); return flexRect; } private static Rect DrawIcon(Rect rect, Texture icon, float w, bool left, bool drawCondition) { if (!drawCondition) return rect; var (iconRect, flexRect) = left ? rect.ExtractLeft(w) : rect.ExtractRight(w); if ((icon != null) && isRepaint) GUI.DrawTexture(iconRect, icon, ScaleMode.ScaleToFit); if (drawDebug) DrawOverlayDebug(iconRect); return flexRect; } private static Rect DrawLabel(Rect rect, GUIContent content, GUIStyle style, Color? color, bool left, bool drawCondition, float yOffset = 0) { if (content == null || content == GUIContent.none || !drawCondition) return rect; float w = style.CalcSize(content).x; var (labelRect, flexRect) = left ? rect.ExtractLeft(w) : rect.ExtractRight(w); if (drawDebug) DrawOverlayDebug(labelRect); if (!isRepaint) return flexRect; Color c = GUI.color; if (color != null) GUI.color = color.Value; { GUI.Label(labelRect.Move(0f, yOffset), content, style); } GUI.color = c; return flexRect; } public static Rect LColumn(this Rect rect, ref float columnW, Func drawer) { var (lRect, flex) = rect.ExtractLeft(columnW); if (drawer == null) return flex; Rect padRect = drawer(lRect); if (padRect.width < 0f) columnW -= padRect.width; return flex; } public static Rect RColumn(this Rect rect, ref float columnW, Func drawer) { var (lRect, flex) = rect.ExtractRight(columnW); if (drawer == null) return flex; Rect padRect = drawer(lRect); if (padRect.width < 0f) columnW -= padRect.width; return flex; } // TAB public static Rect LColumnAlign(this Rect rect, ref float columnX) { if (isLayout) { columnX = 0; return rect; } columnX = Mathf.Max(rect.x, columnX); rect.xMin = columnX; return rect; } public static Rect RColumnAlign(this Rect rect, ref float columnX, string name) { if (rect.xMax <= 0) { columnX = -1; return rect; } if (columnX < 0 || rect.xMax < columnX) { columnX = rect.xMax; } else { rect.xMax = columnX; } return rect; } public static Rect LDrawIcon(this Rect rect, Texture icon, float w = 16f, bool drawCondition = true) { return DrawIcon(rect, icon, w, true, drawCondition); } public static Rect RDrawIcon(this Rect rect, Texture icon, float w = 16f, bool drawCondition = true) { return DrawIcon(rect, icon, w, false, drawCondition); } // Label public static Rect LDrawLabel(this Rect rect, string label, Color? color = null, bool drawCondition = true) { return DrawLabel(rect, AssetFinderGUIContent.FromString(label), EditorStyles.label, color, true, drawCondition); } public static Rect RDrawLabel(this Rect rect, string label, Color? color = null, bool drawCondition = true) { return DrawLabel(rect, AssetFinderGUIContent.FromString(label), EditorStyles.label, color, false, drawCondition); } public static Rect LDrawMiniLabel(this Rect rect, GUIContent label, Color? color = null, bool drawCondition = true) { return DrawLabel(rect, label, EditorStyles.miniLabel, color, true, drawCondition, 1f); } public static Rect LDrawMiniLabel(this Rect rect, string label, Color? color = null, bool drawCondition = true) { return LDrawMiniLabel(rect, AssetFinderGUIContent.FromString(label), color, drawCondition); } public static Rect RDrawMiniLabel(this Rect rect, GUIContent label, Color? color = null, bool drawCondition = true) { return DrawLabel(rect, label, EditorStyles.miniLabel, color, false, drawCondition, 1f); } public static Rect RDrawMiniLabel(this Rect rect, string label, Color? color = null, bool drawCondition = true) { return RDrawMiniLabel(rect, AssetFinderGUIContent.FromString(label), color, drawCondition); } public static Rect LDrawLabel(this Rect rect, GUIContent content, GUIStyle style = null, Color? color = null, bool drawCondition = true) { if (content == null || content == GUIContent.none || !drawCondition) return rect; if (style == null) style = EditorStyles.label; float w = style.CalcSize(content).x; var (labelRect, flexRect) = rect.ExtractLeft(w); if (drawDebug) DrawOverlayDebug(labelRect); if (!isRepaint) return flexRect; Color c = GUI.color; if (color != null) GUI.color = color.Value; { GUI.Label(labelRect, content, style); } GUI.color = c; return flexRect; } public static Rect RDrawLabel(this Rect rect, GUIContent content, GUIStyle style = null, Color? color = null, bool drawCondition = true) { if (content == null || content == GUIContent.none || !drawCondition) return rect; if (style == null) style = EditorStyles.label; float w = style.CalcSize(content).x; var (labelRect, flexRect) = rect.ExtractRight(w); if (drawDebug) DrawOverlayDebug(labelRect); if (!isRepaint) return flexRect; Color c = GUI.color; if (color != null) GUI.color = color.Value; { GUI.Label(labelRect, content, style); } GUI.color = c; return flexRect; } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Extension/AssetFinderExtension.cs.meta ================================================ fileFormatVersion: 2 guid: 7ab1834f1ebc4a3fb6bb0a8d6835c370 timeCreated: 1725377102 ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Extension/AssetFinderHelper.cs ================================================ using System.Collections.Generic; using UnityEditor; using UnityEngine; using UnityEngine.SceneManagement; namespace VirtueSky.AssetFinder.Editor { internal static class AssetFinderHelper { public static IEnumerable getAllObjsInCurScene() { return GameObjectExtensions.GetAllGameObjectsInCurrentScenes(); } private static IEnumerable GetGameObjectsInScene(Scene scene) { var rootObjects = new List(); scene.GetRootGameObjects(rootObjects); // iterate root objects and do something for (var i = 0; i < rootObjects.Count; ++i) { GameObject gameObject = rootObjects[i]; foreach (GameObject item in getAllChild(gameObject)) { yield return item; } yield return gameObject; } } public static IEnumerable getAllChild(GameObject target) { return target.GetAllChildren(false); } public static IEnumerable GetAllRefObjects(GameObject obj) { return obj.GetAllObjectReferences(); } public static int StringMatch(string pattern, string input) { if (string.IsNullOrEmpty(pattern) || string.IsNullOrEmpty(input)) return 0; pattern = pattern.ToLower(); input = input.ToLower(); if (input.Contains(pattern)) return 100; int score = 0; int patternIdx = 0; for (int i = 0; i < input.Length && patternIdx < pattern.Length; i++) { if (input[i] == pattern[patternIdx]) { score += 10; patternIdx++; } } return patternIdx == pattern.Length ? score : 0; } public static string GetfileSizeString(long fileSize) { if (fileSize < 1024) return fileSize + " B"; if (fileSize < 1024 * 1024) return (fileSize / 1024f).ToString("F1") + " KB"; if (fileSize < 1024 * 1024 * 1024) return (fileSize / (1024f * 1024f)).ToString("F1") + " MB"; return (fileSize / (1024f * 1024f * 1024f)).ToString("F1") + " GB"; } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Extension/AssetFinderHelper.cs.meta ================================================ fileFormatVersion: 2 guid: 8828b643803591948bdcb8e6e9d898c3 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Extension/AssetFinderUnity.cs ================================================ #if UNITY_5_3_OR_NEWER #define UNITY_4_3_OR_NEWER #define UNITY_4_4_OR_NEWER #define UNITY_4_5_OR_NEWER #define UNITY_4_6_OR_NEWER #define UNITY_4_7_OR_NEWER #define UNITY_5_0_OR_NEWER #define UNITY_5_1_OR_NEWER #define UNITY_5_2_OR_NEWER #else #if UNITY_5 #define UNITY_4_3_OR_NEWER #define UNITY_4_4_OR_NEWER #define UNITY_4_5_OR_NEWER #define UNITY_4_6_OR_NEWER #define UNITY_4_7_OR_NEWER #if UNITY_5_0 #define UNITY_5_0_OR_NEWER #elif UNITY_5_1 #define UNITY_5_0_OR_NEWER #define UNITY_5_1_OR_NEWER #elif UNITY_5_2 #define UNITY_5_0_OR_NEWER #define UNITY_5_1_OR_NEWER #define UNITY_5_2_OR_NEWER #endif #else #if UNITY_4_3 #define UNITY_4_3_OR_NEWER #elif UNITY_4_4 #define UNITY_4_3_OR_NEWER #define UNITY_4_4_OR_NEWER #elif UNITY_4_5 #define UNITY_4_3_OR_NEWER #define UNITY_4_4_OR_NEWER #define UNITY_4_5_OR_NEWER #elif UNITY_4_6 #define UNITY_4_3_OR_NEWER #define UNITY_4_4_OR_NEWER #define UNITY_4_5_OR_NEWER #define UNITY_4_6_OR_NEWER #elif UNITY_4_7 #define UNITY_4_3_OR_NEWER #define UNITY_4_4_OR_NEWER #define UNITY_4_5_OR_NEWER #define UNITY_4_6_OR_NEWER #define UNITY_4_7_OR_NEWER #endif #endif #endif #if UNITY_5_3_OR_NEWER #define UNITY_SCENE_MANAGER #endif #if AssetFinderADDRESSABLE using UnityEditor.AddressableAssets; #endif using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using UnityEditor; using UnityEditorInternal; using UnityEngine; using Object = UnityEngine.Object; #if UNITY_SCENE_MANAGER using UnityEngine.SceneManagement; using System.IO; #endif namespace VirtueSky.AssetFinder.Editor { internal class AssetFinderUnity { internal static bool isEditorPlaying; internal static bool isEditorUpdating; internal static bool isEditorCompiling; internal static bool isEditorPlayingOrWillChangePlaymode; private static int highlightCounter = 0; public static void RefreshEditorStatus() { isEditorPlaying = EditorApplication.isPlaying; isEditorUpdating = EditorApplication.isUpdating; isEditorCompiling = EditorApplication.isCompiling; isEditorPlayingOrWillChangePlaymode = EditorApplication.isPlayingOrWillChangePlaymode; } public static HashSet _Selection_AssetGUIDs; public static bool StringStartsWith(string source, params string[] prefixes) { if (string.IsNullOrEmpty(source)) return false; for (var i = 0; i < prefixes.Length; i++) { if (source.StartsWith(prefixes[i])) return true; } return false; } public static void SplitPath(string assetPath, out string assetName, out string assetExtension, out string assetFolder) { assetName = string.Empty; assetFolder = string.Empty; assetExtension = string.Empty; if (string.IsNullOrEmpty(assetPath)) return; assetExtension = Path.GetExtension(assetPath); assetName = Path.GetFileNameWithoutExtension(assetPath); int lastSlash = assetPath.LastIndexOf("/", StringComparison.Ordinal) + 1; assetFolder = assetPath.Substring(0, lastSlash); // Debug.Log($"{assetPath} --> \n{assetName}\n{assetExtension}\n{assetFolder}"); } public static string[] Selection_AssetGUIDs { get { #if UNITY_5_0_OR_NEWER Object[] objs = Selection.objects; _Selection_AssetGUIDs = new HashSet(); foreach (Object item in objs) { #if UNITY_2018_1_OR_NEWER { var guid = ""; long fileid = -1; try { // missing references will cause null exception if (AssetDatabase.TryGetGUIDAndLocalFileIdentifier(item, out guid, out fileid)) _Selection_AssetGUIDs.Add(guid + "/" + fileid); //Debug.Log("guid: " + guid + " fileID: " + fileid); } catch { } } #else { var path = AssetDatabase.GetAssetPath(item); if (string.IsNullOrEmpty(path)) continue; var guid = AssetDatabase.AssetPathToGUID(path); System.Reflection.PropertyInfo inspectorModeInfo = typeof(SerializedObject).GetProperty("inspectorMode", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); SerializedObject serializedObject = new SerializedObject(item); inspectorModeInfo.SetValue(serializedObject, InspectorMode.Debug, null); SerializedProperty localIdProp = serializedObject.FindProperty("m_LocalIdentfierInFile"); //note the misspelling! var localId = localIdProp.longValue; if (localId <= 0) { localId = localIdProp.intValue; } if (localId <= 0) { continue; } if (!string.IsNullOrEmpty(guid)) _Selection_AssetGUIDs.Add(guid + "/" + localId); } #endif } return Selection.assetGUIDs; #else var mInfo = typeof(Selection).GetProperty("assetGUIDs", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); if (mInfo != null){ return (string[]) mInfo.GetValue(null, null); } AssetFinderLOG.LogWarning("Unity changed ! Selection.assetGUIDs not found !"); return new string[0]; #endif } } public static void PingAndHighlight( Component component, string propertyPath, float glowSeconds = 5f) { if (component == null) return; // auto-lock var window = EditorWindow.focusedWindow as AssetFinderWindowAll; if (window != null) window.smartLock.SetPingLockState(AssetFinderSmartLock.PingLockState.Scene); Selection.activeGameObject = component.gameObject; ExpandPropertyPath(component, propertyPath); SetEditorsExpanded(component); EditorApplication.delayCall += () => { if (window != null) window.smartLock.SetPingLockState(AssetFinderSmartLock.PingLockState.Scene); Selection.activeGameObject = component.gameObject; EditorApplication.delayCall += () => { highlightCounter++; var currentHighlightId = highlightCounter; var success = TriggerHighlight(propertyPath); if (success) { StopHighlightAt(currentHighlightId, EditorApplication.timeSinceStartup + glowSeconds); return; } Debug.Log($"Can not highlight property <{propertyPath}> in Inspector <{component.GetType().Name}>\nThe Inspector might be locked or the property is hidden\n\n"); }; }; } private static bool TriggerHighlight(string propertyPath) { var result = false; using (AssetFinderDev.NoLog) { result = Highlight(propertyPath); if (!result) // Array? { var path2 = propertyPath.Replace(".Array.data[", "["); result = Highlight(path2); } if (!result) result = Highlight(propertyPath.Split('.')[0]); } return result; } private static bool Highlight(string propertyPath) { var result = Highlighter.Highlight("Inspector", propertyPath, HighlightSearchMode.Auto); if (!result) result = Highlighter.Highlight("Inspector", ObjectNames.NicifyVariableName(propertyPath), HighlightSearchMode.Auto); return result; } private static void StopHighlightAt(int highlightId, double stopTime) { void Check() { if (highlightCounter > highlightId) { EditorApplication.update -= Check; return; } if (EditorApplication.timeSinceStartup < stopTime) return; Highlighter.Stop(); EditorApplication.update -= Check; } EditorApplication.update += Check; } private static void CollapseAllComponentsExcept(Component targetComponent) { if (targetComponent == null) return; var gameObject = targetComponent.gameObject; var allComponents = gameObject.GetComponents(); foreach (var comp in allComponents) { var expect = comp == targetComponent; var before = InternalEditorUtility.GetIsInspectorExpanded(comp); InternalEditorUtility.SetIsInspectorExpanded(comp, expect); var after = InternalEditorUtility.GetIsInspectorExpanded(comp); if (after != expect) { Debug.LogWarning($"comp: {comp.GetType().Name} | before: {before} --> after: {InternalEditorUtility.GetIsInspectorExpanded(comp)} | expect: {expect}"); } } } private static void DoExpand(Component c) { var tracker = ActiveEditorTracker.sharedTracker; for (var i = 0; i < tracker.activeEditors.Length; i++) { var editor = tracker.activeEditors[i]; var isExpand = editor.target == c; InternalEditorUtility.SetIsInspectorExpanded(editor.target, isExpand); editor.serializedObject.ApplyModifiedProperties(); editor.Repaint(); } } private static void SetEditorsExpanded(Component c) { DoExpand(c); Selection.activeGameObject = null; } private static void SetEditorsExpanded2(Component c) { var tracker = ActiveEditorTracker.sharedTracker; for (int i = 0; i < tracker.activeEditors.Length; i++) { var expanded = c == tracker.activeEditors[i].target; tracker.SetVisible(i, expanded ? 1 : 0); } var inspectorWindow = GetInspectorWindow(); if (inspectorWindow != null) inspectorWindow.Repaint(); } private static EditorWindow GetInspectorWindow() { System.Type inspectorType = typeof(EditorWindow).Assembly.GetType("UnityEditor.InspectorWindow"); return EditorWindow.GetWindow(inspectorType); } private static void ExpandPropertyPath(Component component, string propertyPath) { if (component == null) return; var serializedObject = new SerializedObject(component); serializedObject.Update(); var prop = serializedObject.GetIterator(); var deep = true; while (prop.NextVisible(deep)) { if (!propertyPath.Contains(prop.propertyPath)) { prop.isExpanded = false; deep = false; continue; } prop.isExpanded = true; deep = true; } serializedObject.ApplyModifiedPropertiesWithoutUndo(); } private static readonly Lazy> HashClassesNormalLazy = new Lazy>(() => new Dictionary { { 1, "UnityEngine.GameObject" }, { 2, "UnityEngine.Component" }, { 4, "UnityEngine.Transform" }, { 8, "UnityEngine.Behaviour" }, { 12, "UnityEngine.ParticleAnimator" }, { 15, "UnityEngine.EllipsoidParticleEmitter" }, { 20, "UnityEngine.Camera" }, { 21, "UnityEngine.Material" }, { 23, "UnityEngine.MeshRenderer" }, { 25, "UnityEngine.Renderer" }, { 26, "UnityEngine.ParticleRenderer" }, { 27, "UnityEngine.Texture" }, { 28, "UnityEngine.Texture2D" }, { 33, "UnityEngine.MeshFilter" }, { 41, "UnityEngine.OcclusionPortal" }, { 43, "UnityEngine.Mesh" }, { 45, "UnityEngine.Skybox" }, { 47, "UnityEngine.QualitySettings" }, { 48, "UnityEngine.Shader" }, { 49, "UnityEngine.TextAsset" }, { 50, "UnityEngine.Rigidbody2D" }, { 53, "UnityEngine.Collider2D" }, { 54, "UnityEngine.Rigidbody" }, { 56, "UnityEngine.Collider" }, { 57, "UnityEngine.Joint" }, { 58, "UnityEngine.CircleCollider2D" }, { 59, "UnityEngine.HingeJoint" }, { 60, "UnityEngine.PolygonCollider2D" }, { 61, "UnityEngine.BoxCollider2D" }, { 62, "UnityEngine.PhysicsMaterial2D" }, { 64, "UnityEngine.MeshCollider" }, { 65, "UnityEngine.BoxCollider" }, { 68, "UnityEngine.EdgeCollider2D" }, { 72, "UnityEngine.ComputeShader" }, { 74, "UnityEngine.AnimationClip" }, { 75, "UnityEngine.ConstantForce" }, { 81, "UnityEngine.AudioListener" }, { 82, "UnityEngine.AudioSource" }, { 83, "UnityEngine.AudioClip" }, { 84, "UnityEngine.RenderTexture" }, { 87, "UnityEngine.MeshParticleEmitter" }, { 88, "UnityEngine.ParticleEmitter" }, { 89, "UnityEngine.Cubemap" }, { 90, "Avatar" }, { 92, "UnityEngine.GUILayer" }, { 93, "UnityEngine.RuntimeAnimatorController" }, { 95, "UnityEngine.Animator" }, { 96, "UnityEngine.TrailRenderer" }, { 102, "UnityEngine.TextMesh" }, { 104, "UnityEngine.RenderSettings" }, { 108, "UnityEngine.Light" }, { 111, "UnityEngine.Animation" }, { 114, "UnityEngine.MonoBehaviour" }, { 115, "UnityEditor.MonoScript" }, { 117, "UnityEngine.Texture3D" }, { 119, "UnityEngine.Projector" }, { 120, "UnityEngine.LineRenderer" }, { 121, "UnityEngine.Flare" }, { 123, "UnityEngine.LensFlare" }, { 124, "UnityEngine.FlareLayer" }, { 128, "UnityEngine.Font" }, { 129, "UnityEditor.PlayerSettings" }, { 131, "UnityEngine.GUITexture" }, { 132, "UnityEngine.GUIText" }, { 133, "UnityEngine.GUIElement" }, { 134, "UnityEngine.PhysicMaterial" }, { 135, "UnityEngine.SphereCollider" }, { 136, "UnityEngine.CapsuleCollider" }, { 137, "UnityEngine.SkinnedMeshRenderer" }, { 138, "UnityEngine.FixedJoint" }, { 142, "UnityEngine.AssetBundle" }, { 143, "UnityEngine.CharacterController" }, { 144, "UnityEngine.CharacterJoint" }, { 145, "UnityEngine.SpringJoint" }, { 146, "UnityEngine.WheelCollider" }, { 152, "UnityEngine.MovieTexture" }, { 153, "UnityEngine.ConfigurableJoint" }, { 154, "UnityEngine.TerrainCollider" }, { 156, "UnityEngine.TerrainData" }, { 157, "UnityEngine.LightmapSettings" }, { 158, "UnityEngine.WebCamTexture" }, { 159, "UnityEditor.EditorSettings" }, { 162, "UnityEditor.EditorUserSettings" }, { 164, "UnityEngine.AudioReverbFilter" }, { 165, "UnityEngine.AudioHighPassFilter" }, { 166, "UnityEngine.AudioChorusFilter" }, { 167, "UnityEngine.AudioReverbZone" }, { 168, "UnityEngine.AudioEchoFilter" }, { 169, "UnityEngine.AudioLowPassFilter" }, { 170, "UnityEngine.AudioDistortionFilter" }, { 171, "UnityEngine.SparseTexture" }, { 180, "UnityEngine.AudioBehaviour" }, { 182, "UnityEngine.WindZone" }, { 183, "UnityEngine.Cloth" }, { 192, "UnityEngine.OcclusionArea" }, { 193, "UnityEngine.Tree" }, { 198, "UnityEngine.ParticleSystem" }, { 199, "UnityEngine.ParticleSystemRenderer" }, { 200, "UnityEngine.ShaderVariantCollection" }, { 205, "UnityEngine.LODGroup" }, { 207, "UnityEngine.Motion" }, { 212, "UnityEngine.SpriteRenderer" }, { 213, "UnityEngine.Sprite" }, { 215, "UnityEngine.ReflectionProbe" }, { 218, "UnityEngine.Terrain" }, { 220, "UnityEngine.LightProbeGroup" }, { 221, "UnityEngine.AnimatorOverrideController" }, { 222, "UnityEngine.CanvasRenderer" }, { 223, "UnityEngine.Canvas" }, { 224, "UnityEngine.RectTransform" }, { 225, "UnityEngine.CanvasGroup" }, { 226, "UnityEngine.BillboardAsset" }, { 227, "UnityEngine.BillboardRenderer" }, { 229, "UnityEngine.AnchoredJoint2D" }, { 230, "UnityEngine.Joint2D" }, { 231, "UnityEngine.SpringJoint2D" }, { 232, "UnityEngine.DistanceJoint2D" }, { 233, "UnityEngine.HingeJoint2D" }, { 234, "UnityEngine.SliderJoint2D" }, { 235, "UnityEngine.WheelJoint2D" }, { 246, "UnityEngine.PhysicsUpdateBehaviour2D" }, { 247, "UnityEngine.ConstantForce2D" }, { 248, "UnityEngine.Effector2D" }, { 249, "UnityEngine.AreaEffector2D" }, { 250, "UnityEngine.PointEffector2D" }, { 251, "UnityEngine.PlatformEffector2D" }, { 252, "UnityEngine.SurfaceEffector2D" }, { 258, "UnityEngine.LightProbes" }, { 290, "UnityEngine.AssetBundleManifest" }, { 1003, "UnityEditor.AssetImporter" }, { 1004, "UnityEditor.AssetDatabase" }, { 1006, "UnityEditor.TextureImporter" }, { 1007, "UnityEditor.ShaderImporter" }, { 1011, "UnityEngine.AvatarMask" }, { 1020, "UnityEditor.AudioImporter" }, { 1029, "UnityEditor.DefaultAsset" }, { 1032, "UnityEditor.SceneAsset" }, { 1035, "UnityEditor.MonoImporter" }, { 1040, "UnityEditor.ModelImporter" }, { 1042, "UnityEditor.TrueTypeFontImporter" }, { 1044, "UnityEditor.MovieImporter" }, { 1045, "UnityEditor.EditorBuildSettings" }, { 1050, "UnityEditor.PluginImporter" }, { 1051, "UnityEditor.EditorUserBuildSettings" }, { 1105, "UnityEditor.HumanTemplate" }, { 1110, "UnityEditor.SpeedTreeImporter" }, { 1113, "UnityEditor.LightmapParameters" } }); public static Dictionary HashClassesNormal => HashClassesNormalLazy.Value; //private static Texture2D _whiteTexture; //public static Texture2D whiteTexture { // get { // return EditorGUIUtility.whiteTexture; // #if UNITY_5_0_OR_NEWER // return EditorGUIUtility.whiteTexture; // #else // if (_whiteTexture != null) return _whiteTexture; // _whiteTexture = new Texture2D(1,1, TextureFormat.RGBA32, false); // _whiteTexture.SetPixel(0, 0, Color.white); // _whiteTexture.hideFlags = HideFlags.DontSave; // return _whiteTexture; // #endif // } //} public static T LoadAssetAtPath(string path) where T : Object { #if UNITY_5_1_OR_NEWER return AssetDatabase.LoadAssetAtPath(path); #else return (T)AssetDatabase.LoadAssetAtPath(path, typeof(T)); #endif } public static void SetWindowTitle(EditorWindow window, string title) { #if UNITY_5_1_OR_NEWER window.titleContent = AssetFinderGUIContent.FromString(title); #else window.title = title; #endif } public static void GetCompilingPhase(string path, out bool isPlugin, out bool isEditor) { #if (UNITY_5_2_0 || UNITY_5_2_1) && !UNITY_5_2_OR_NEWER bool oldSystem = true; #else var oldSystem = false; #endif // ---- Old system: Editor for the plugin should be Plugins/Editor if (oldSystem) { bool isPluginEditor = path.StartsWith("Assets/Plugins/Editor/", StringComparison.Ordinal) || path.StartsWith("Assets/Standard Assets/Editor/", StringComparison.Ordinal) || path.StartsWith("Assets/Pro Standard Assets/Editor/", StringComparison.Ordinal); if (isPluginEditor) { isPlugin = true; isEditor = true; return; } } isPlugin = path.StartsWith("Assets/Plugins/", StringComparison.Ordinal) || path.StartsWith("Assets/Standard Assets/", StringComparison.Ordinal) || path.StartsWith("Assets/Pro Standard Assets/", StringComparison.Ordinal); isEditor = oldSystem && isPlugin ? false : path.Contains("/Editor/"); } public static T LoadAssetWithGUID(string guid) where T : Object { if (string.IsNullOrEmpty(guid)) return null; string path = AssetDatabase.GUIDToAssetPath(guid); if (string.IsNullOrEmpty(path)) return null; #if UNITY_5_1_OR_NEWER return AssetDatabase.LoadAssetAtPath(path); #else return (T)AssetDatabase.LoadAssetAtPath(path, typeof(T)); #endif } public static void UnloadUnusedAssets() { #if UNITY_5_0_OR_NEWER EditorUtility.UnloadUnusedAssetsImmediate(); #else EditorUtility.UnloadUnusedAssets(); #endif Resources.UnloadUnusedAssets(); } internal static int Epoch(DateTime time) { return (int)(time.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds; } internal static bool DrawToggle(ref bool v, string label) { bool v1 = GUILayout.Toggle(v, label); if (v1 != v) { v = v1; return true; } return false; } internal static bool DrawToggleToolbar(ref bool v, string label, float width) { bool v1 = GUILayout.Toggle(v, label, EditorStyles.toolbarButton, GUILayout.Width(width)); if (v1 != v) { v = v1; return true; } return false; } internal static bool DrawToggleToolbar(ref bool v, GUIContent icon, float width) { bool v1 = GUILayout.Toggle(v, icon, EditorStyles.toolbarButton, GUILayout.Width(width)); if (v1 != v) { v = v1; return true; } return false; } public static string GetAddressable(string guid) { #if AssetFinderADDRESSABLE var aaSettings = AddressableAssetSettingsDefaultObject.GetSettings(true); var entry = aaSettings.FindAssetEntry(guid); return entry != null ? entry.address : string.Empty; #endif return null; } internal static EditorWindow FindEditor(string className) { EditorWindow[] list = Resources.FindObjectsOfTypeAll(); foreach (EditorWindow item in list) { if (item.GetType().FullName == className) return item; } return null; } internal static void RepaintAllEditor(string className) { EditorWindow[] list = Resources.FindObjectsOfTypeAll(); foreach (EditorWindow item in list) { #if AssetFinderDEV Debug.Log(item.GetType().FullName); #endif if (item.GetType().FullName != className) continue; item.Repaint(); } } internal static void RepaintProjectWindows() { RepaintAllEditor("UnityEditor.ProjectBrowser"); } internal static void RepaintFR2Windows() { RepaintAllEditor("vietlabs.fr2.AssetFinderWindow"); } internal static void ExportSelection() { Type packageExportT = null; foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()) { packageExportT = assembly.GetType("UnityEditor.PackageExport"); if (packageExportT != null) break; } if (packageExportT == null) { AssetFinderLOG.LogWarning("Export Package Error : UnityEditor.PackageExport not found !"); return; } EditorWindow panel = EditorWindow.GetWindow(packageExportT, true, "Exporting package"); #if UNITY_5_2_OR_NEWER var prop = "m_IncludeDependencies"; #else var prop = "m_bIncludeDependencies"; #endif FieldInfo fieldInfo = packageExportT.GetField(prop, BindingFlags.NonPublic | BindingFlags.Instance); if (fieldInfo == null) { AssetFinderLOG.LogWarning("Export Package error : " + prop + " not found !"); return; } MethodInfo methodInfo = packageExportT.GetMethod("BuildAssetList", BindingFlags.NonPublic | BindingFlags.Instance); if (methodInfo == null) { AssetFinderLOG.LogWarning("Export Package error : BuildAssetList method not found !"); return; } fieldInfo.SetValue(panel, false); methodInfo.Invoke(panel, null); panel.Repaint(); } public static Type GetType(string typeName) { var type = Type.GetType(typeName); if (type != null) return type; foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies()) { type = a.GetType(typeName); if (type != null) return type; } return null; } public static IEnumerable GetAllChild(Transform root) { yield return root; if (root.childCount <= 0) yield break; for (var i = 0; i < root.childCount; i++) { foreach (Transform item in GetAllChild(root.GetChild(i))) { yield return item; } } } public static IEnumerable getAllObjsInCurScene() { #if UNITY_SCENE_MANAGER for (var j = 0; j < SceneManager.sceneCount; j++) { Scene scene = SceneManager.GetSceneAt(j); foreach (GameObject item in GetGameObjectsInScene(scene)) { yield return item; } } if (EditorApplication.isPlaying) { //dont destroy scene GameObject temp = null; try { temp = new GameObject(); Object.DontDestroyOnLoad(temp); Scene dontDestroyOnLoad = temp.scene; Object.DestroyImmediate(temp); temp = null; foreach (GameObject item in GetGameObjectsInScene(dontDestroyOnLoad)) { yield return item; } } finally { if (temp != null) Object.DestroyImmediate(temp); } } #else foreach (Transform obj in Resources.FindObjectsOfTypeAll(typeof(Transform))) { GameObject o = obj.gameObject; yield return o; } #endif } #if UNITY_SCENE_MANAGER private static IEnumerable GetGameObjectsInScene(Scene scene) { var rootObjects = new List(); if (!scene.isLoaded) yield break; scene.GetRootGameObjects(rootObjects); // iterate root objects and do something for (var i = 0; i < rootObjects.Count; ++i) { GameObject gameObject = rootObjects[i]; foreach (GameObject item in getAllChild(gameObject)) { yield return item; } yield return gameObject; } } #endif public static IEnumerable getAllChild(GameObject target, bool returnMe = false) { return target.GetAllChildren(returnMe); } public static IEnumerable GetAllRefObjects(GameObject obj) { return obj.GetAllObjectReferences(); } public static int StringMatch(string pattern, string input) { if (string.IsNullOrEmpty(pattern) || string.IsNullOrEmpty(input)) return 0; pattern = pattern.ToLower(); input = input.ToLower(); if (input.Contains(pattern)) return 100; int score = 0; int patternIdx = 0; for (int i = 0; i < input.Length && patternIdx < pattern.Length; i++) { if (input[i] == pattern[patternIdx]) { score += 10; patternIdx++; } } return patternIdx == pattern.Length ? score : 0; } #if AssetFinderDEBUG [MenuItem("Tools/Test Prefab")] static void TestPrefab() { GetPrefabParent(Selection.activeGameObject); } #endif public static string GetPrefabParent(Object obj) { if (obj is GameObject go) return GetPrefabGUID(go); if (obj is Component comp) return GetPrefabGUID(comp.gameObject); return string.Empty; } public static string GetGameObjectPath(GameObject obj, bool includeMe = true) { return GetHierarchyPath(obj, includeMe); } public static bool CheckIsPrefab(GameObject obj) { return IsPrefabInstance(obj); } private static string GetPrefabGUID(GameObject obj) { #if UNITY_2020_3_OR_NEWER var prefabParent = PrefabUtility.GetCorrespondingObjectFromSource(obj); if (prefabParent != null) { return AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(prefabParent)); } #elif UNITY_2018_3_OR_NEWER var prefabStage = UnityEditor.Experimental.SceneManagement.PrefabStageUtility.GetCurrentPrefabStage(); if (prefabStage != null && prefabStage.prefabContentsRoot == obj) { return AssetDatabase.AssetPathToGUID(prefabStage.prefabAssetPath); } var prefabRoot = PrefabUtility.GetOutermostPrefabInstanceRoot(obj); if (prefabRoot != null) { var prefabAsset = PrefabUtility.GetCorrespondingObjectFromSource(prefabRoot); if (prefabAsset != null) { return AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(prefabAsset)); } } #else var prefabParent = PrefabUtility.GetPrefabParent(obj); if (prefabParent != null) { return AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(prefabParent)); } #endif return string.Empty; } private static string GetHierarchyPath(GameObject obj, bool includeMe = true) { if (obj == null) return string.Empty; var path = string.Empty; var current = obj.transform; while (current != null) { if (current == obj.transform && !includeMe) { current = current.parent; continue; } path = current.name + (string.IsNullOrEmpty(path) ? "" : "/" + path); current = current.parent; } return path; } private static bool IsPrefabInstance(GameObject obj) { #if UNITY_2018_3_OR_NEWER return PrefabUtility.IsPartOfPrefabInstance(obj); #else return PrefabUtility.GetPrefabType(obj) == PrefabType.PrefabInstance; #endif } public static void Clear(ref Dictionary dict) { GameObjectExtensions.InitializeOrClear(ref dict); } public static void Clear(ref List list) { GameObjectExtensions.InitializeOrClear(ref list); } public static SerializedProperty[] xGetSerializedProperties(Object go, bool processArray) { var so = new SerializedObject(go); return so.GetAllProperties(processArray); } public static List xGetSOArray(SerializedProperty prop) { int size = prop.arraySize; var result = new List(); for (var i = 0; i < size; i++) { SerializedProperty p = prop.GetArrayElementAtIndex(i); if (p.isArray) { result.AddRange(xGetSOArray(p.Copy())); } else { result.Add(p.Copy()); } } return result; } public static void BackupAndDeleteAssets(AssetFinderRef[] assets) { var fileName = DateTime.Now.ToString("yyMMdd_hhmmss"); AssetFinderRef[] list = assets; var result = new List(); var selectedList = new List(); foreach (AssetFinderRef item in list) { if (item.asset == null) continue; string oPath = item.asset.assetPath.Replace("\\", "/"); if (!oPath.StartsWith("Assets/")) continue; result.Add(item.asset.assetPath); if (item.isSelected()) selectedList.Add(item.asset.assetPath); } if (selectedList.Count != 0) result = selectedList; Directory.CreateDirectory("Library/FR2/"); AssetDatabase.ExportPackage(result.ToArray(), "Library/FR2/bk_" + fileName + ".unitypackage"); AssetDatabase.StartAssetEditing(); try { for (var i = 0; i < result.Count; i++) { AssetDatabase.DeleteAsset(result[i]); } } finally { AssetDatabase.StopAssetEditing(); AssetDatabase.Refresh(); } AssetFinderCache.DelayCheck4Changes(); } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Extension/AssetFinderUnity.cs.meta ================================================ fileFormatVersion: 2 guid: 65be7edb17b7a8b4092a809fc881f206 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Extension/GUI2.cs ================================================ using System; using System.Collections.Generic; using UnityEditor; using UnityEngine; using UnityEngine.Profiling; using Object = UnityEngine.Object; namespace VirtueSky.AssetFinder.Editor { public interface IDrawer { bool Draw(Rect rect); bool DrawLayout(); } internal static class AssetFinderGUI { public static GUIColor Color(Color c) { return new GUIColor(c); } public static GUIContentColor ContentColor(Color c) { return new GUIContentColor(c); } public static GUIBackgroundColor BackgroundColor(Color c) { return new GUIBackgroundColor(c); } internal class GUIColor : IDisposable { private readonly Color color; public GUIColor(Color c) { color = GUI.color; GUI.color = c; } public void Dispose() { GUI.color = color; } } internal class GUIContentColor : IDisposable { private readonly Color color; public GUIContentColor(Color c) { color = GUI.contentColor; GUI.contentColor = c; } public void Dispose() { GUI.contentColor = color; } } internal class GUIBackgroundColor : IDisposable { private readonly Color color; public GUIBackgroundColor(Color c) { color = GUI.backgroundColor; GUI.backgroundColor = c; } public void Dispose() { GUI.backgroundColor = color; } } } internal static class GUI2 { internal static Dictionary tooltipCache = new Dictionary(); // ----------------------- private static GUIStyle _miniLabelAlignRight; public static Color darkRed = new Color(0.5f, .0f, 0f, 1f); public static Color darkGreen = new Color(0, .5f, 0f, 1f); public static Color darkBlue = new Color(0, .0f, 0.5f, 1f); public static Color lightRed = new Color(1f, 0.5f, 0.5f, 1f); public static readonly GUILayoutOption[] GLW_20 = { GUILayout.Width(20f) }; public static readonly GUILayoutOption[] GLW_24 = { GUILayout.Width(24f) }; public static readonly GUILayoutOption[] GLW_50 = { GUILayout.Width(50f) }; // Legacy compact size public static readonly GUILayoutOption[] GLW_70 = { GUILayout.Width(70f) }; // Legacy medium size public static readonly GUILayoutOption[] GLW_80 = { GUILayout.Width(80f) }; // Legacy standard size public static readonly GUILayoutOption[] GLW_100 = { GUILayout.Width(100f) }; public static readonly GUILayoutOption[] GLW_120 = { GUILayout.Width(120f) }; // Legacy wide size public static readonly GUILayoutOption[] GLW_140 = { GUILayout.Width(140f) }; // Legacy extra wide size public static readonly GUILayoutOption[] GLW_150 = { GUILayout.Width(150f) }; public static readonly GUILayoutOption[] GLW_160 = { GUILayout.Width(160f) }; public static readonly GUILayoutOption[] GLW_320 = { GUILayout.Width(320f) }; public static GUIStyle miniLabelAlignRight { get { if (_miniLabelAlignRight != null) return _miniLabelAlignRight; return _miniLabelAlignRight = new GUIStyle(EditorStyles.miniLabel) { alignment = TextAnchor.MiddleRight }; } } public static void Color(Action a, Color c, float? alpha = null) { if (a == null) return; Color cColor = GUI.color; if (alpha != null) c.a = alpha.Value; GUI.color = c; a(); GUI.color = cColor; } public static void ContentColor(Action a, Color c, float? alpha = null) { if (a == null) return; Color cColor = GUI.contentColor; if (alpha != null) c.a = alpha.Value; GUI.contentColor = c; a(); GUI.contentColor = cColor; } public static void BackgroundColor(Action a, Color c, float? alpha = null) { if (a == null) return; Color cColor = GUI.backgroundColor; if (alpha != null) c.a = alpha.Value; GUI.backgroundColor = c; a(); GUI.backgroundColor = cColor; } public static Color Theme(Color proColor, Color indieColor) { return EditorGUIUtility.isProSkin ? proColor : indieColor; } public static Color Alpha(Color c, float a) { c.a = a; return c; } public static void Rect(Rect r, Color c, float? alpha = null) { Color cColor = GUI.color; if (alpha != null) c.a = alpha.Value; GUI.color = c; GUI.DrawTexture(r, Texture2D.whiteTexture); GUI.color = cColor; } public static Object[] DropZone(string title, float w, float h) { Rect rect = GUILayoutUtility.GetRect(w, h); GUI.Box(rect, GUIContent.none, EditorStyles.textArea); float cx = rect.x + w / 2f; float cy = rect.y + h / 2f; float pz = w / 3f; // plus size var plusRect = new Rect(cx - pz / 2f, cy - pz / 2f, pz, pz); Color(() => { GUI.DrawTexture(plusRect, AssetFinderIcon.Plus.image, ScaleMode.ScaleToFit); }, UnityEngine.Color.white, 0.1f); GUI.Label(rect, title, EditorStyles.wordWrappedMiniLabel); EventType eventType = Event.current.type; var isAccepted = false; if (eventType == EventType.DragUpdated || eventType == EventType.DragPerform) { DragAndDrop.visualMode = DragAndDropVisualMode.Copy; if (eventType == EventType.DragPerform) { DragAndDrop.AcceptDrag(); isAccepted = true; } Event.current.Use(); } return isAccepted ? DragAndDrop.objectReferences : null; } // public static bool ColorIconButton(Rect r, Texture icon, Vector2? iconOffset, Color? c) // { // if (c != null) Rect(r, c.Value); // // // align center // if (iconOffset != null) // { // r.x += iconOffset.Value.x; // r.y += iconOffset.Value.y; // } // // return GUI.Button(r, icon, GUIStyle.none); // } public static bool ColorIconButton(Rect r, Texture icon, Color? c) { Color oColor = GUI.color; if (c != null) GUI.color = c.Value; bool result = GUI.Button(r, icon, GUIStyle.none); GUI.color = oColor; return result; } public static bool Toggle(Rect r, ref bool value, string label, GUIStyle style, params GUILayoutOption[] options) { GUIContent guiContent = AssetFinderGUIContent.From(label); bool vv = GUI.Toggle(r, value, guiContent, style); if (vv == value) return false; value = vv; return true; } public static bool Toggle(ref bool value, string label, GUIStyle style, params GUILayoutOption[] options) { GUIContent guiContent = AssetFinderGUIContent.From(label); bool vv = GUILayout.Toggle(value, guiContent, style, options); if (vv == value) return false; value = vv; return true; } public static bool Toggle(ref bool value, Texture2D tex, GUIStyle style, params GUILayoutOption[] options) { bool vv = GUILayout.Toggle(value, tex, style, options); if (vv == value) return false; value = vv; return true; } public static bool Toggle(Rect r, ref bool value, GUIContent tex, GUIStyle style) { bool vv = GUI.Toggle(r, value, tex, style); if (vv == value) return false; value = vv; return true; } public static bool Toggle(ref bool value, GUIContent tex, GUIStyle style, params GUILayoutOption[] options) { bool vv = GUILayout.Toggle(value, tex, style, options); if (vv == value) return false; value = vv; return true; } public static bool Toggle(Rect rect, ref bool value, GUIContent tex) { bool vv = GUI.Toggle(rect, value, tex, GUIStyle.none); if (vv == value) return false; value = vv; return true; } public static bool Toggle(Rect rect, ref bool value) { bool vv = GUI.Toggle(rect, value, GUIContent.none); if (vv == value) return false; value = vv; return true; } internal static bool Toggle(bool v, string label, Action setter) { GUIContent guiContent = AssetFinderGUIContent.From(label); bool v1 = GUILayout.Toggle(v, guiContent); if (v1 == v) return false; if (setter != null) setter(v1); return true; } internal static bool ToolbarToggle(Rect r, ref bool value, Texture icon, Vector2 padding, string tooltip = null) { //TODO: FIX GC bool vv = GUI.Toggle(r, value, AssetFinderGUIContent.Tooltip(tooltip), EditorStyles.toolbarButton); if (icon != null) { Rect rect = GUILayoutUtility.GetLastRect(); rect = Padding(rect, padding.x, padding.y); GUI.DrawTexture(rect, icon, ScaleMode.ScaleToFit); } if (vv == value) return false; value = vv; return true; } internal static bool GUI_ToggleOptimize(Rect r, bool value, GUIContent content) { EventType eventType = Event.current.type; if (eventType == EventType.MouseDown) { return GUI.Toggle(r, value, content, EditorStyles.toolbarButton); } if (eventType == EventType.Repaint) { GUI.DrawTexture(r, content.image, ScaleMode.ScaleToFit); } return false; } public static bool ToolbarToggle(ref bool value, Texture icon, Vector2 padding, string tooltip, Rect position) { // Draw the toggle button directly at the specified position bool newValue = GUI.Toggle(position, value, AssetFinderGUIContent.FromTexture(icon, tooltip), EditorStyles.toolbarButton); // Update the reference value bool changed = newValue != value; value = newValue; return changed; } // Example implementation of a Toggle public static bool Toggle(ref bool value, GUIContent content, GUIStyle style, Rect position) { // Draw the toggle button directly at the specified position bool newValue = GUI.Toggle(position, value, content, style); // Update the reference value bool changed = newValue != value; value = newValue; return changed; } internal static bool ToolbarToggle(Rect r, ref bool value, GUIContent content) { if (value == false) { if (GUI.Toggle(r, value, content, EditorStyles.toolbarButton) != value) { value = true; return true; } return false; } if (GUI.Toggle(r, value, content, EditorStyles.toolbarButton) == false) { value = false; return true; } return false; } internal static bool ToolbarToggle(ref bool value, Texture icon, Vector2 padding, string tooltip = null) { var vv = false; Profiler.BeginSample("FR2-GUI2.ToolbarToggle"); { vv = GUILayout.Toggle(value, AssetFinderGUIContent.Tooltip(tooltip), EditorStyles.toolbarButton, GLW_24); if (icon != null) { Rect rect = GUILayoutUtility.GetLastRect(); rect = Padding(rect, padding.x, padding.y); GUI.DrawTexture(rect, icon, ScaleMode.ScaleToFit); } } Profiler.EndSample(); if (vv == value) return false; value = vv; return true; } internal static bool ToolbarToggle(ref bool value, Texture icon, Vector2 padding, string tooltip, Rect position, bool hasContent = false) { // Apply special coloring when button is OFF but has content to show Color originalColor = GUI.backgroundColor; if (!value && hasContent) { GUI.backgroundColor = UnityEngine.Color.yellow; // Yellow background when off but has content } // Draw the toggle button directly at the specified position bool newValue = GUI.Toggle(position, value, AssetFinderGUIContent.FromTexture(icon, tooltip), EditorStyles.toolbarButton); // Update the reference value bool changed = newValue != value; value = newValue; // Restore original color GUI.backgroundColor = originalColor; return changed; } // internal static bool GUILayoutToggle(ref bool value, string tooltip) // { // Profiler.BeginSample("FR2-GUI2.ToolbarToggle2-step1"); // Rect rect = GUILayoutUtility.GetRect(24, 24, 18f, 18f); // Profiler.EndSample(); // // Profiler.BeginSample("FR2-GUI2.ToolbarToggle2-step2"); // bool oldValue = value; // value = GUI.Toggle(rect, value, AssetFinderGUIContent.Tooltip(tooltip), EditorStyles.toolbarButton); // Profiler.EndSample(); // // return oldValue != value; // } // TODO : optimize for performance // public static bool EnumPopup(ref T mode, string label, float labelWidth, GUIStyle style, params GUILayoutOption[] options) // { // var sz = EditorGUIUtility.labelWidth; // EditorGUIUtility.labelWidth = labelWidth; // { // var obj = (Enum)(object)mode; // var vv = EditorGUILayout.EnumPopup(label, obj, style, options); // if (Equals(vv, obj)) // { // EditorGUIUtility.labelWidth = sz; // return false; // } // mode = (T)(object)vv; // } // EditorGUIUtility.labelWidth = sz; // return true; // } // public static bool EnumPopup(ref T mode, GUIContent icon, GUIStyle style, params GUILayoutOption[] options) // { // var obj = (Enum)(object)mode; // var cRect = GUILayoutUtility.GetRect(16f, 16f); // if (Event.current.type == EventType.Repaint) // { // cRect.xMin -= 2f; // cRect.yMin += 2f; // GUI.Label(cRect, icon); // } // if (Event.current.type == EventType.MouseDown && Event.current.button == 0) // { // var vv = EditorGUILayout.EnumPopup(obj, style, options); // if (Equals(vv, obj)) // { // return false; // } // mode = (T)(object)vv; // return true; // } // //if (Event.current.type == EventType.Repaint) // { // EditorGUILayout.LabelField(AssetFinderGUIContent.FromString("Hello"), style, options); // } // return false; // } public static Rect Padding(Rect r, float x, float y) { return new Rect(r.x + x, r.y + y, r.width - 2 * x, r.height - 2 * y); } public static Rect LeftRect(float w, ref Rect rect) { rect.x += w; rect.width -= w; return new Rect(rect.x - w, rect.y, w, rect.height); } public static Rect RightRect(float w, ref Rect rect) { rect.width -= w; return new Rect(rect.x + rect.width, rect.y, w, rect.height); } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Extension/GUI2.cs.meta ================================================ fileFormatVersion: 2 guid: 9fa484b2aa858464fb8254e4bbf1f6ac MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Extension.meta ================================================ fileFormatVersion: 2 guid: 7c7413730e214b0ab9b5a7a25cbd9a44 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Extensions/AssetFinderWindowExtensions.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using UnityEditor; using UnityEngine; using UnityObject = UnityEngine.Object; namespace VirtueSky.AssetFinder.Editor { internal static class AssetFinderWindowExtensions { // Panel visibility extensions internal static bool IsScenePanelVisible(this AssetFinderWindowAll window) { if (window.isFocusingAddressable) return false; if (window.selection.isSelectingAsset && window.isFocusingUses) // Override { return false; } if (!window.selection.isSelectingAsset && window.isFocusingUsedBy) { return true; } return window.settings.scene; } internal static bool IsAssetPanelVisible(this AssetFinderWindowAll window) { if (window.isFocusingAddressable) return false; if (window.selection.isSelectingAsset && window.isFocusingUses) // Override { return true; } if (!window.selection.isSelectingAsset && window.isFocusingUsedBy) { return false; } return window.settings.asset; } internal static void RefreshPanelVisibility(this AssetFinderWindowAll window) { window.sp2.splits[0].visible = window.IsScenePanelVisible(); window.sp2.splits[1].visible = window.IsAssetPanelVisible(); window.sp2.splits[2].visible = window.isFocusingAddressable; window.sp2.CalculateWeight(); } // Selection management extensions internal static UnityObject[] GetCachedSelectionExtension(this AssetFinderWindowAll window) { int currentFrame = Time.frameCount; if (window._cachedSelectionFrame != currentFrame) { window._cachedSelection = Selection.objects; window._cachedSelectionFrame = currentFrame; } return window._cachedSelection; } // Asset drawer extension internal static AssetFinderRefDrawer GetAssetDrawerExtension(this AssetFinderWindowAll window) { if (window.isFocusingUses) return window.selection.isSelectingAsset ? window.UsesDrawer : window.SceneToAssetDrawer; if (window.isFocusingUsedBy) return window.selection.isSelectingAsset ? window.UsedByDrawer : null; if (window.isFocusingAddressable) return window.AddressableDrawer.drawer; return null; } internal static void OnCSVClickExtension(this AssetFinderWindowAll window) { AssetFinderRef[] csvSource = null; AssetFinderRefDrawer drawer = window.GetAssetDrawerExtension(); if (drawer != null) csvSource = drawer.source; if (window.isFocusingUnused && (csvSource == null)) csvSource = window.RefUnUse.source; if (window.isFocusingUsedInBuild && (csvSource == null)) csvSource = AssetFinderRef.FromDict(window.UsedInBuild.refs); if (window.isFocusingDuplicate && (csvSource == null)) csvSource = AssetFinderRef.FromList(window.Duplicated.list); AssetFinderExport.ExportCSV(csvSource); } internal static void CacheAllDrawers(this AssetFinderWindowAll window) { window._allDrawersCache = new AssetFinderRefDrawer[] { window.UsedByDrawer, window.UsesDrawer, window.SceneToAssetDrawer, window.RefUnUse, window.RefInScene, window.RefSceneInScene, window.SceneUsesDrawer, window.UsedInBuild.Drawer }; } internal static void RefreshShowUsageType(this AssetFinderWindowAll window) { if (window._allDrawersCache != null) { foreach (var drawer in window._allDrawersCache) { if (drawer != null && drawer.AssetConfig != null) drawer.AssetConfig.showUsageType = window.settings.showUsageType; } } } internal static void RefreshSort(this AssetFinderWindowAll window) { if (window._allDrawersCache != null) { foreach (var drawer in window._allDrawersCache) { drawer?.RefreshSort(); } } window.AddressableDrawer.RefreshSort(); window.Duplicated.RefreshSort(); window.UsedInBuild.RefreshSort(); // Ensure tool-specific drawers are also refreshed if (window.settings.toolMode) { window.RefUnUse?.RefreshSort(); } } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Extensions/AssetFinderWindowExtensions.cs.meta ================================================ fileFormatVersion: 2 guid: 393ff0810b1b94cefabaa2d9449560ee MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Extensions/CollectionExtensions.cs ================================================ using System.Collections.Generic; namespace VirtueSky.AssetFinder.Editor { internal static class CollectionExtensions { internal static HashSet ToHashSet(this IEnumerable collection) { var result = new HashSet(); if (collection == null) return result; foreach (T item in collection) { result.Add(item); } return result; } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Extensions/CollectionExtensions.cs.meta ================================================ fileFormatVersion: 2 guid: 1dbc4e32a727c4ecdb4be457da481199 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Extensions/ColorExtensions.cs ================================================ using UnityEngine; namespace VirtueSky.AssetFinder.Editor { internal static class ColorExtensions { internal static Color Alpha(this Color c, float alpha) { return new Color(c.r, c.g, c.b, alpha); } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Extensions/ColorExtensions.cs.meta ================================================ fileFormatVersion: 2 guid: d9b900ca884e345308acc476c8af4e53 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Extensions/DictionaryExtensions.cs ================================================ using System; using System.Collections.Generic; namespace VirtueSky.AssetFinder.Editor { internal static class DictionaryExtensions { #if UNITY_2021_2_OR_NEWER // GetValueOrDefault exists in newer Unity versions #else internal static TValue GetValueOrDefault(this Dictionary dictionary, TKey key, TValue defaultValue = default(TValue)) { return dictionary.TryGetValue(key, out TValue value) ? value : defaultValue; } #endif internal static TValue TryGetValueOrAdd(this Dictionary dictionary, TKey key, TValue defaultValue) { if (dictionary.TryGetValue(key, out TValue value)) return value; dictionary[key] = defaultValue; return defaultValue; } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Extensions/DictionaryExtensions.cs.meta ================================================ fileFormatVersion: 2 guid: 3f57a4bab3eb042b981518071fa681fa MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Extensions/GameObjectExtensions.cs ================================================ using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement; using UnityEditor; using UnityObject = UnityEngine.Object; namespace VirtueSky.AssetFinder.Editor { internal static class GameObjectExtensions { internal static IEnumerable GetAllChildren(this GameObject target, bool includeTarget = false) { if (target == null) yield break; if (includeTarget) yield return target; if (target.transform.childCount > 0) { for (var i = 0; i < target.transform.childCount; i++) { var child = target.transform.GetChild(i).gameObject; if (child == null) continue; yield return child; foreach (var grandChild in child.GetAllChildren(false)) { yield return grandChild; } } } } internal static IEnumerable GetAllChildTransforms(this Transform root) { yield return root; for (var i = 0; i < root.childCount; i++) { var child = root.GetChild(i); foreach (var descendant in child.GetAllChildTransforms()) { yield return descendant; } } } internal static IEnumerable GetAllGameObjectsInCurrentScenes() { for (var j = 0; j < SceneManager.sceneCount; j++) { var scene = SceneManager.GetSceneAt(j); foreach (var gameObject in scene.GetAllGameObjects()) { yield return gameObject; } } if (EditorApplication.isPlaying) { GameObject temp = null; try { temp = new GameObject(); UnityObject.DontDestroyOnLoad(temp); var dontDestroyOnLoad = temp.scene; UnityObject.DestroyImmediate(temp); temp = null; foreach (var gameObject in dontDestroyOnLoad.GetAllGameObjects()) { yield return gameObject; } } finally { if (temp != null) UnityObject.DestroyImmediate(temp); } } } internal static IEnumerable GetAllGameObjects(this Scene scene) { if (!scene.isLoaded) yield break; var rootObjects = new List(); scene.GetRootGameObjects(rootObjects); for (var i = 0; i < rootObjects.Count; ++i) { var rootObject = rootObjects[i]; foreach (var child in rootObject.GetAllChildren(false)) { yield return child; } yield return rootObject; } } internal static void InitializeOrClear(ref List list) { if (list == null) { list = new List(); } else { list.Clear(); } } internal static void InitializeOrClear(ref Dictionary dictionary) { if (dictionary == null) { dictionary = new Dictionary(); } else { dictionary.Clear(); } } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Extensions/GameObjectExtensions.cs.meta ================================================ fileFormatVersion: 2 guid: 20b7c860188d14e36883165f4230bab3 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Extensions/RectExtensions.cs ================================================ using UnityEngine; namespace VirtueSky.AssetFinder.Editor { internal static class RectExtensions { internal static (Rect, Rect) HzSplit(this Rect r, float space = 8f, float ratio = 0.5f) { var w = (r.width - space) * ratio; var r1 = new Rect(r.x, r.y, w, r.height); var r2 = new Rect(r.x + w + space, r.y, r.width - w - space, r.height); return (r1, r2); } internal static (Rect left, Rect flex) ExtractLeft(this Rect r, float leftWidth = 16f, float space = 0f) { var left = new Rect(r.x, r.y, leftWidth, r.height); var flex = new Rect(r.x + leftWidth + space, r.y, r.width - leftWidth - space, r.height); return (left, flex); } internal static (Rect right, Rect flex) ExtractRight(this Rect r, float rightWidth = 16f, float space = 0f) { var right = new Rect(r.x + r.width - rightWidth, r.y, rightWidth, r.height); var flex = new Rect(r.x, r.y, r.width - rightWidth - space, r.height); return (right, flex); } internal static Rect LPad(this Rect r, float padding = 8f, bool padCondition = true) { return padCondition ? new Rect(r.x + padding, r.y, r.width - padding, r.height) : r; } internal static Rect RPad(this Rect r, float padding = 8f, bool padCondition = true) { return padCondition ? new Rect(r.x, r.y, r.width - padding, r.height) : r; } internal static Rect Pad(this Rect r, float padLeft = 8f, float padRight = 8f, bool padCondition = true) { return padCondition ? new Rect(r.x + padLeft, r.y, r.width - padLeft - padRight, r.height) : r; } internal static Rect Move(this Rect r, float dx = 0f, float dy = 0f) { return new Rect(r.x + dx, r.y + dy, r.width, r.height); } internal static Rect SetHeight(this Rect r, float h) { return new Rect(r.x, r.y, r.width, h); } internal static Rect SetWidth(this Rect r, float w) { return new Rect(r.x, r.y, w, r.height); } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Extensions/RectExtensions.cs.meta ================================================ fileFormatVersion: 2 guid: d3ef94fba7a6949beb1eeb13be0b2e6a MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Extensions/RectGUIExtensions.cs ================================================ using System; using UnityEngine; using UnityEditor; namespace VirtueSky.AssetFinder.Editor { internal static class RectGUIExtensions { internal static Rect OnRightClick(this Rect rect, Action onRightClick, float padding = 0f) { var padRect = rect.Pad(padding, padding); if (Event.current.type == EventType.MouseDown && Event.current.button == 1) { if (padRect.Contains(Event.current.mousePosition)) { onRightClick?.Invoke(); Event.current.Use(); } } return rect; } internal static Rect OnLeftClick(this Rect rect, Action onClick, float padding = 0f) { var padRect = rect.Pad(padding, padding); if (Event.current.type == EventType.MouseDown && Event.current.button == 0) { if (padRect.Contains(Event.current.mousePosition)) { onClick?.Invoke(); Event.current.Use(); } } return rect; } internal static Rect OnDoubleClick(this Rect rect, Action onDoubleClick, float padding = 0f) { var padRect = rect.Pad(padding, padding); if (Event.current.type == EventType.MouseDown && Event.current.button == 0 && Event.current.clickCount == 2) { if (padRect.Contains(Event.current.mousePosition)) { onDoubleClick?.Invoke(); Event.current.Use(); } } return rect; } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Extensions/RectGUIExtensions.cs.meta ================================================ fileFormatVersion: 2 guid: c7cd0bdf6c8394e4cbde439e5052c9bb MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Extensions/SerializedObjectExtensions.cs ================================================ using System.Collections.Generic; using UnityEditor; using UnityEngine; using UnityObject = UnityEngine.Object; namespace VirtueSky.AssetFinder.Editor { internal static class SerializedObjectExtensions { internal static IEnumerable GetAllObjectReferences(this SerializedObject serializedObject) { SerializedProperty iterator = serializedObject.GetIterator().Copy(); while (iterator.NextVisible(true)) { if (iterator.propertyType != SerializedPropertyType.ObjectReference) continue; if (iterator.objectReferenceValue == null) continue; yield return iterator.objectReferenceValue; } } internal static IEnumerable GetAllObjectReferences(this Component component) { if (component == null) yield break; var serializedObject = new SerializedObject(component); foreach (var obj in serializedObject.GetAllObjectReferences()) { yield return obj; } } internal static IEnumerable GetAllObjectReferences(this GameObject gameObject) { if (gameObject == null) yield break; var components = gameObject.GetComponents(); foreach (var component in components) { foreach (var obj in component.GetAllObjectReferences()) { yield return obj; } } } internal static SerializedProperty[] GetAllProperties(this SerializedObject serializedObject, bool processArrays = false) { serializedObject.Update(); var result = new List(); SerializedProperty iterator = serializedObject.GetIterator(); while (iterator.NextVisible(true)) { SerializedProperty copy = iterator.Copy(); if (processArrays && iterator.isArray) { result.AddRange(GetArrayProperties(copy)); } else { result.Add(copy); } } return result.ToArray(); } private static List GetArrayProperties(SerializedProperty arrayProperty) { var result = new List(); int size = arrayProperty.arraySize; for (int i = 0; i < size; i++) { SerializedProperty element = arrayProperty.GetArrayElementAtIndex(i); if (element.isArray) { result.AddRange(GetArrayProperties(element.Copy())); } else { result.Add(element.Copy()); } } return result; } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Extensions/SerializedObjectExtensions.cs.meta ================================================ fileFormatVersion: 2 guid: ce68eca29b021402ea48c05018c4ca1e MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Extensions/TabExtensions.cs ================================================ using System; namespace VirtueSky.AssetFinder.Editor { internal static class TabExtensions { internal static bool IsFocusing(this AssetFinderTabView tabView, int index) { return tabView != null && tabView.current == index; } internal static bool IsFocusingAny(this AssetFinderTabView tabView, params int[] indices) { if (tabView == null) return false; foreach (int index in indices) { if (tabView.current == index) return true; } return false; } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Extensions/TabExtensions.cs.meta ================================================ fileFormatVersion: 2 guid: 760bc254844c546a2a7f851252c1ca3b MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Extensions/UnityObjectExtensions.cs ================================================ using UnityEngine; using UnityEditor; using System.Linq; using System.Collections.Generic; using UnityObject = UnityEngine.Object; namespace VirtueSky.AssetFinder.Editor { internal static class UnityObjectExtensions { public static bool IsSceneObject(this UnityObject obj) { // null, destroyed or asset-stored objects all return false return obj != null && !EditorUtility.IsPersistent(obj) && (obj is GameObject || obj is Component); } public static bool IsAssetObject(this UnityObject obj) { return obj != null && EditorUtility.IsPersistent(obj); } internal static GameObject GetGameObjectFromTarget(this UnityObject target) { if (!target) return null; if (target is GameObject go) return go; if (target is Component comp && comp != null) return comp.gameObject; return null; } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Extensions/UnityObjectExtensions.cs.meta ================================================ fileFormatVersion: 2 guid: f00e2486baaa5468d977d31d88435a06 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Extensions.meta ================================================ fileFormatVersion: 2 guid: c31023e7608e64d93882b110fcd25d84 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Modules/Addressable/AssetFinderAddressable.ASMStatus.cs ================================================ namespace VirtueSky.AssetFinder.Editor { public static partial class AssetFinderAddressable { public enum ASMStatus { None, AsmNotFound, TypeNotFound, FieldNotFound, AsmOK } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Modules/Addressable/AssetFinderAddressable.ASMStatus.cs.meta ================================================ fileFormatVersion: 2 guid: 5165551de58ead041ad896718828125d MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Modules/Addressable/AssetFinderAddressable.AddressInfo.cs ================================================ using System; using System.Collections.Generic; namespace VirtueSky.AssetFinder.Editor { public static partial class AssetFinderAddressable { [Serializable] public class AddressInfo { public string address; public string bundleGroup; public HashSet assetGUIDs; public HashSet childGUIDs; } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Modules/Addressable/AssetFinderAddressable.AddressInfo.cs.meta ================================================ fileFormatVersion: 2 guid: e6b0b5f786f9112409dbf87d86874dd8 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Modules/Addressable/AssetFinderAddressable.ProjectStatus.cs ================================================ namespace VirtueSky.AssetFinder.Editor { public static partial class AssetFinderAddressable { public enum ProjectStatus { None, NoSettings, NoGroup, Ok } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Modules/Addressable/AssetFinderAddressable.ProjectStatus.cs.meta ================================================ fileFormatVersion: 2 guid: 7b7933c9a7e39144db38a73ad4ffb618 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Modules/Addressable/AssetFinderAddressable.cs ================================================ using System; using System.Collections.Generic; using System.Reflection; using UnityEditor; namespace VirtueSky.AssetFinder.Editor { public static partial class AssetFinderAddressable { private static Assembly asm; private static Type addressableAssetGroupType; private static Type addressableAssetEntryType; private static PropertyInfo entriesProperty; private static PropertyInfo groupNameProperty; private static PropertyInfo addressProperty; private static PropertyInfo guidProperty; private static PropertyInfo settingsProperty; private static PropertyInfo groupsProperty; static AssetFinderAddressable() { Scan(); } public static bool isOk => (asmStatus == ASMStatus.AsmOK) && (projectStatus == ProjectStatus.Ok); public static ASMStatus asmStatus { get; private set; } public static ProjectStatus projectStatus { get; private set; } public static void Scan() { asm = GetAssembly(); if (asm == null) { asmStatus = ASMStatus.AsmNotFound; return; } Type addressableSettingsType = GetAddressableType("UnityEditor.AddressableAssets.Settings.AddressableAssetSettings"); Type addressableSettingsDefaultObjectType = GetAddressableType("UnityEditor.AddressableAssets.AddressableAssetSettingsDefaultObject"); addressableAssetGroupType = GetAddressableType("UnityEditor.AddressableAssets.Settings.AddressableAssetGroup"); addressableAssetEntryType = GetAddressableType("UnityEditor.AddressableAssets.Settings.AddressableAssetEntry"); if (addressableSettingsType == null || addressableSettingsDefaultObjectType == null || addressableAssetGroupType == null || addressableAssetEntryType == null) { asmStatus = ASMStatus.TypeNotFound; return; } entriesProperty = addressableAssetGroupType.GetProperty("entries", BindingFlags.Public | BindingFlags.Instance); groupNameProperty = addressableAssetGroupType.GetProperty("Name", BindingFlags.Public | BindingFlags.Instance); addressProperty = addressableAssetEntryType.GetProperty("address", BindingFlags.Public | BindingFlags.Instance); guidProperty = addressableAssetEntryType.GetProperty("guid", BindingFlags.Public | BindingFlags.Instance); settingsProperty = addressableSettingsDefaultObjectType.GetProperty("Settings", BindingFlags.Public | BindingFlags.Static); groupsProperty = addressableSettingsType.GetProperty("groups", BindingFlags.Public | BindingFlags.Instance); if (entriesProperty == null || groupNameProperty == null || addressProperty == null || guidProperty == null) { asmStatus = ASMStatus.FieldNotFound; return; } asmStatus = ASMStatus.AsmOK; projectStatus = ProjectStatus.None; } private static Assembly GetAssembly() { const string DLL = "Unity.Addressables.Editor"; Assembly[] allAssemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly item in allAssemblies) { if (item.GetName().Name != DLL) continue; return item; } return null; } private static Type GetAddressableType(string typeName) { return asm == null ? null : asm.GetType(typeName); } /// /// Get a map between address -> AddressInfo (assetGUIDs + childGUIDs) /// /// public static Dictionary GetAddresses() { if (asmStatus != ASMStatus.AsmOK) return null; // Get the AddressableAssetSettings instance object settings = settingsProperty?.GetValue(null); if (settings == null) { projectStatus = ProjectStatus.NoSettings; return null; } var addresses = new Dictionary(); var groups = groupsProperty?.GetValue(settings) as IEnumerable; if (groups == null) { projectStatus = ProjectStatus.NoGroup; return null; } projectStatus = ProjectStatus.Ok; // Loop through each group foreach (object group in groups) { if (group == null || addressableAssetGroupType == null || addressableAssetEntryType == null) continue; // Get the group's 'entries' property var entries = entriesProperty?.GetValue(group) as IEnumerable; if (entries == null) continue; // Get the group's 'Name' property var groupName = groupNameProperty?.GetValue(group)?.ToString(); // Loop through each entry in the group foreach (object entry in entries) { if (entry == null) continue; // Get the entry's 'address' and 'guid' properties var address = addressProperty?.GetValue(entry)?.ToString(); var guid = guidProperty?.GetValue(entry)?.ToString(); if (address == null || guid == null) continue; if (!addresses.TryGetValue(address, out AddressInfo fr2Address)) { // New address entry fr2Address = new AddressInfo { address = address, bundleGroup = groupName, assetGUIDs = new HashSet(), childGUIDs = new HashSet() }; addresses.Add(address, fr2Address); } if (fr2Address.assetGUIDs.Add(guid)) // folder? { AppendChildGUIDs(fr2Address.childGUIDs, guid); } } } return addresses; } private static void AppendChildGUIDs(HashSet h, string guid) { string folderPath = AssetDatabase.GUIDToAssetPath(guid); if (!AssetDatabase.IsValidFolder(folderPath)) return; string[] allGUIDs = AssetDatabase.FindAssets("*", new[] { folderPath }); foreach (string child in allGUIDs) { AssetFinderAsset asset = AssetFinderCache.Api.Get(child, true); if (asset == null) { AssetFinderLOG.LogWarning($"Why asset is null? {guid}\n{folderPath}"); continue; } if (asset.IsExcluded || asset.IsMissing || asset.IsScript || asset.type == AssetFinderAsset.AssetType.UNKNOWN) continue; if (asset.inEditor || asset.inResources || asset.inStreamingAsset || asset.inPlugins) continue; if (asset.extension == ".asmdef") continue; if (asset.extension == ".wlt") continue; if (asset.IsFolder) continue; h.Add(child); } } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Modules/Addressable/AssetFinderAddressable.cs.meta ================================================ fileFormatVersion: 2 guid: 658fb11a3764f404881e3adcb3d9471d MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Modules/Addressable.meta ================================================ fileFormatVersion: 2 guid: ad6c77f8001445e78a614bfb210c5be1 timeCreated: 1746365309 ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Modules/AssetFinderCSV.cs ================================================ using System; using System.Text; using UnityEditor; using UnityEngine; namespace VirtueSky.AssetFinder.Editor { internal class AssetFinderCSV { private const string SEPARATOR = ","; public static string GetCSVRow(AssetFinderRef r, params string[] suffixes) { AssetFinderAsset asset = r.asset; AssetFinderSceneRef sr = r.isSceneRef ? (AssetFinderSceneRef)r : null; var go = (GameObject)null; if (sr != null) { if (sr.component is Component) go = ((Component)sr.component).gameObject; if (sr.component is GameObject) go = (GameObject)sr.component; } var sb = new StringBuilder(); sb.Append(r.depth); sb.Append(SEPARATOR); sb.Append(r.isSceneRef ? sr.component.name : asset.assetName); sb.Append(SEPARATOR); sb.Append(r.isSceneRef ? AssetFinderRef.FindUsageScene(new[] { go }, false).Count : asset.UsageCount()); sb.Append(SEPARATOR); sb.Append(r.isSceneRef ? string.Empty : asset.extension); sb.Append(SEPARATOR); sb.Append(r.isSceneRef ? "0" : asset.fileSize.ToString()); sb.Append(SEPARATOR); string type = r.isSceneRef ? "SceneObject" : "(missing)"; if (!r.isSceneRef) { Type obj = AssetDatabase.GetMainAssetTypeAtPath(asset.assetPath); if (obj != null) type = obj.ToString(); if (type.StartsWith("UnityEngine.") || type.StartsWith("UnityEditor.")) { int idx = type.LastIndexOf(".", StringComparison.Ordinal) + 1; type = type.Substring(idx, type.Length - idx); } } sb.Append(type); sb.Append(SEPARATOR); sb.Append(r.isSceneRef ? string.Empty : asset.guid); sb.Append(SEPARATOR); sb.Append(r.isSceneRef ? string.Empty : asset.AtlasName); sb.Append(SEPARATOR); sb.Append(r.isSceneRef ? string.Empty : asset.AssetBundleName); sb.Append(SEPARATOR); sb.Append(r.group); sb.Append(SEPARATOR); sb.Append(r.isSceneRef ? sr.sceneFullPath : asset.assetPath); foreach (string t in suffixes) { sb.Append(SEPARATOR); sb.Append(t); } return sb.ToString(); } public static string GetCSVTitle() { var sb = new StringBuilder(); sb.Append("depth"); sb.Append(SEPARATOR); sb.Append("name"); sb.Append(SEPARATOR); sb.Append("usage count"); sb.Append(SEPARATOR); sb.Append("extension"); sb.Append(SEPARATOR); sb.Append("size"); sb.Append(SEPARATOR); sb.Append("type"); sb.Append(SEPARATOR); sb.Append("guid"); sb.Append(SEPARATOR); sb.Append("atlas"); sb.Append(SEPARATOR); sb.Append("assetbundle"); sb.Append(SEPARATOR); sb.Append("group"); sb.Append(SEPARATOR); sb.Append("full path"); return sb.ToString(); } public static string GetCSVRows(AssetFinderRef[] source) { if (source == null) //Debug.LogWarning("source should not be null!"); { return string.Empty; } var sb = new StringBuilder(); sb.AppendLine(GetCSVTitle()); foreach (AssetFinderRef s in source) { if (s == null) continue; sb.AppendLine(GetCSVRow(s)); } return sb.ToString(); } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Modules/AssetFinderCSV.cs.meta ================================================ fileFormatVersion: 2 guid: 64c9804c538c4e94ca30ab45cbd5cdc1 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Modules/AssetFinderExport.cs ================================================ //#define AssetFinderDEV using System; using System.Collections.Generic; using System.Linq; using UnityEditor; using UnityEngine; using Object = UnityEngine.Object; namespace VirtueSky.AssetFinder.Editor { internal class AssetFinderExport { private const int maxThread = 5; private static Dictionary listReplace; private static HashSet cacheSelection; // private static List lstThreads; public static bool IsMergeProcessing { get; private set; } public static void ExportCSV(AssetFinderRef[] csvSource) { string result = AssetFinderCSV.GetCSVRows(csvSource); if (result.Length > 0) { EditorGUIUtility.systemCopyBuffer = result; Debug.Log("[FR2] CSV file content (" + csvSource.Length + " assets) copied to clipboard!"); } else { AssetFinderLOG.LogWarning("[FR2] Nothing to export!"); } } #if AssetFinderDEV [MenuItem("Assets/AssetFinder/Debug details", false, 19)] private static void DebugDetails() { var s = Selection.activeObject; if (s == null) return; var path = AssetDatabase.GetAssetPath(s); if (string.IsNullOrEmpty(path)) { AssetFinderLOG.LogWarning("Path: " + path); return; } var guid = AssetDatabase.AssetPathToGUID(path); var asset = AssetFinderCache.Api.Get(guid); if (asset == null) { AssetFinderLOG.LogWarning($"Asset is null??? {guid}"); return; } Debug.Log(asset.DebugUseGUID()); } #endif [MenuItem("Assets/AssetFinder/Toggle Ignore", false, 19)] private static void Ignore() { if (!AssetFinderCache.isReady) { AssetFinderLOG.LogWarning("AssetFinder cache not yet ready, please open Window > AssetFinderWindow and hit scan project!"); return; } Object[] actives = Selection.objects; for (var i = 0; i < actives.Length; i++) { string path = AssetDatabase.GetAssetPath(actives[i]); if (path.Equals(AssetFinderCache.DEFAULT_CACHE_PATH)) continue; if (AssetFinderSetting.IgnoreAsset.Contains(path)) { AssetFinderSetting.RemoveIgnore(path); } else { AssetFinderSetting.AddIgnore(path); } } } [MenuItem("Assets/AssetFinder/Copy GUID", false, 20)] private static void CopyGUID() { EditorGUIUtility.systemCopyBuffer = AssetDatabase.AssetPathToGUID( AssetDatabase.GetAssetPath(Selection.activeObject) ); } [MenuItem("Assets/AssetFinder/Export Selection", false, 21)] private static void ExportSelection() { if (!AssetFinderCache.isReady) { AssetFinderLOG.LogWarning("AssetFinder cache not yet ready, please open Window > AssetFinderWindow and hit scan project!"); return; } AssetFinderUnity.ExportSelection(); } [MenuItem("Assets/AssetFinder/Select Dependencies (assets I use)", false, 22)] private static void SelectDependencies_wtme() { if (!AssetFinderCache.isReady) { AssetFinderLOG.LogWarning("FR2 cache not yet ready, please open Window > AssetFinderWindow and hit scan project!"); return; } SelectDependencies(false); } [MenuItem("Assets/AssetFinder/Refresh")] public static void ForceRefreshSelection() { string[] guids = Selection.assetGUIDs; if (!AssetFinderCache.isReady) return; // cache not ready! for (var i = 0; i < guids.Length; i++) { string guid = guids[i]; if (guid == AssetFinderCache.CachePath) continue; if (!AssetFinderAsset.IsValidGUID(guid)) continue; if (AssetFinderCache.Api.AssetMap.ContainsKey(guid)) { AssetFinderCache.Api.RefreshAsset(guid, true); #if AssetFinderDEBUG UnityEngine.Debug.Log("Changed : " + guids[i]); #endif continue; } AssetFinderCache.Api.AddAsset(guid); } AssetFinderCache.Api.Check4Work(); } [MenuItem("Assets/AssetFinder/Select Dependencies included me", false, 23)] private static void SelectDependencies_wme() { if (!AssetFinderCache.isReady) { AssetFinderLOG.LogWarning("FR2 cache not yet ready, please open Window > AssetFinderWindow and hit scan project!"); return; } SelectDependencies(true); } //[MenuItem("Assets/AssetFinder/Select")] [MenuItem("Assets/AssetFinder/Select Used (assets used me)", false, 24)] private static void SelectUsed_wtme() { if (!AssetFinderCache.isReady) { AssetFinderLOG.LogWarning("AssetFinder cache not yet ready, please open Window > AssetFinderWindow and hit scan project!"); return; } SelectUsed(false); } [MenuItem("Assets/AssetFinder/Select Used included me", false, 25)] private static void SelectUsed_wme() { if (!AssetFinderCache.isReady) { AssetFinderLOG.LogWarning("FR2 cache not yet ready, please open Window > AssetFinderWindow and hit scan project!"); return; } SelectUsed(true); } [MenuItem("Assets/AssetFinder/Export Dependencies", false, 40)] private static void ExportDependencies() { if (!AssetFinderCache.isReady) { AssetFinderLOG.LogWarning("FR2 cache not yet ready, please open Window > AssetFinderWindow and hit scan project!"); return; } List deps = GetSelectionDependencies(); if (deps == null) return; Selection.objects = deps.ToArray(); AssetFinderUnity.ExportSelection(); } [MenuItem("Assets/AssetFinder/Export Assets (no scripts)", false, 41)] private static void ExportAsset() { if (!AssetFinderCache.isReady) { AssetFinderLOG.LogWarning("AssetFinder cache not yet ready, please open Window > AssetFinderWindow and hit scan project!"); return; } List list = GetSelectionDependencies(); for (int i = list.Count - 1; i >= 0; i--) { if (list[i] is MonoScript) list.RemoveAt(i); } //Debug.Log(i + ":" + list[i] + ":" + list[i].GetType()); Selection.objects = list.ToArray(); AssetFinderUnity.ExportSelection(); } public static void MergeDuplicate(string guid_file) { // for (int i = 0; i < Selection.objects.Length; i++) // { // Object item = Selection.objects[i]; // Debug.Log(item.name); // } //string guid_file = EditorGUIUtility.systemCopyBuffer; long toFileId = 0; string[] string_arr = guid_file.Split('/'); if (string_arr.Length > 1) toFileId = long.Parse(string_arr[1]); string guid = string_arr[0]; // var wat = new System.Diagnostics.Stopwatch(); // wat.Start(); //validate clipboard guid string gPath = AssetDatabase.GUIDToAssetPath(guid); if (string.IsNullOrEmpty(gPath) || !gPath.StartsWith("Assets/")) { AssetFinderLOG.LogWarning("Invalid guid <" + guid + "> in clipboard, can not replace !"); return; } string[] temp = AssetFinderUnity.Selection_AssetGUIDs; //cheat refresh selection, DO NOT delete HashSet guids_files = AssetFinderUnity._Selection_AssetGUIDs; var realKey = ""; foreach (string item in guids_files) { if (item.StartsWith(guid_file, StringComparison.Ordinal)) realKey = item; } if (string.IsNullOrEmpty(realKey)) { Debug.LogWarning("Clipboard guid <" + guid + "> not found in Selection, you may not intentionally replace selection assets by clipboard guid"); // foreach (var item in guids_files) { // Debug.Log ("item: " + item); // } return; } guids_files.Remove(realKey); cacheSelection = new HashSet(); foreach (string item in cacheSelection) { cacheSelection.Add(item); } if (guids_files.Count == 0) { AssetFinderLOG.LogWarning("No new asset selected to replace, must select all duplications to replace"); return; } //check asset type, only replace same type #if REPLACE_SAME_TYPE var type1 = AssetDatabase.GetMainAssetTypeAtPath(gPath); var importType1 = AssetImporter.GetAtPath(gPath); #endif var assetList = new List(); var lstFind = new List(); foreach (string item in guids_files) { string[] arr = item.Split('/'); string g = arr[0]; #if REPLACE_SAME_TYPE var p2 = AssetDatabase.GUIDToAssetPath(g); var type2 = AssetDatabase.GetMainAssetTypeAtPath(p2); if(type1 != type2) { AssetFinderLOG.LogWarning("Cannot replace asset: " + p2 + " becase difference type"); continue; } if(type1 == typeof(UnityEngine.Texture2D)) { var importType2 = AssetImporter.GetAtPath(p2) as TextureImporter; var textureImportType1 = importType1 as TextureImporter; if (importType2 == null || textureImportType1 == null) { AssetFinderLOG.LogWarning("Cannot replace asset: " + p2 + " becase difference type"); continue; } if(textureImportType1.textureType != importType2.textureType) { AssetFinderLOG.LogWarning("Cannot replace asset: " + p2 + " becase difference type"); continue; } if (textureImportType1.textureType == TextureImporterType.Sprite) { if (textureImportType1.spriteImportMode != importType2.spriteImportMode) { AssetFinderLOG.LogWarning("Cannot replace asset: " + p2 + " becase difference type"); continue; } } //Debug.Log("import type " + mainImportType); } //Debug.Log("type: " + mainType); #endif lstFind.Add(g); } if (lstFind.Count == 0) { AssetFinderLOG.LogWarning("No new asset selected to replace, must select all duplications to replace"); return; } assetList = AssetFinderCache.Api.FindAssets(lstFind.ToArray(), false); //replace one by one listReplace = new Dictionary(); for (int i = assetList.Count - 1; i >= 0; i--) { // Debug.Log("FR2 Replace GUID : " + assetList[i].guid + " ---> " + guid + " : " + assetList[i].UsedByMap.Count + " assets updated"); string fromId = assetList[i].guid; List arr = assetList[i].UsedByMap.Values.ToList(); for (var j = 0; j < arr.Count; j++) { AssetFinderAsset a = arr[j]; if (!listReplace.ContainsKey(a.assetPath)) listReplace.Add(a.assetPath, new ProcessReplaceData()); listReplace[a.assetPath].datas.Add(new ReplaceData { from = fromId, to = guid, asset = a, toFileId = toFileId }); } } // foreach (KeyValuePair item in listReplace) // { // item.Value.processIndex = item.Value.datas.Count - 1; // } IsMergeProcessing = true; EditorApplication.update -= ApplicationUpdate; EditorApplication.update += ApplicationUpdate; // for (var i = assetList.Count - 1; i >= 0; i--) // { // // Debug.Log("FR2 Replace GUID : " + assetList[i].guid + " ---> " + guid + " : " + assetList[i].UsedByMap.Count + " assets updated"); // var from = assetList[i].guid; // var arr = assetList[i].UsedByMap.Values.ToList(); // for (var j = 0; j < arr.Count; j ++) // { // var a = arr[j]; // var result = a.ReplaceReference(from, guid); // if (result && !dictAsset.ContainsKey(a.guid)) // { // dictAsset.Add(a.guid, 1); // } // } // } // Debug.Log("Time replace guid " + wat.ElapsedMilliseconds); // wat = new System.Diagnostics.Stopwatch(); // wat.Start(); // var listRefresh = dictAsset.Keys.ToList(); // for (var i = 0; i < listRefresh.Count; i++) // { // AssetFinderCache.Api.RefreshAsset(listRefresh[i], true); // } // AssetFinderCache.Api.RefreshSelection(); // AssetFinderCache.Api.Check4Usage(); // AssetDatabase.Refresh(); // Debug.Log("Time replace guid " + wat.ElapsedMilliseconds); } private static void ApplicationUpdate() { var isCompleted = true; foreach (KeyValuePair item in listReplace) { if (item.Value.processed) continue; item.Value.processed = true; for (var i = 0; i < item.Value.datas.Count; i++) { ReplaceData a = item.Value.datas[i]; a.isTerrian = a.asset.type == AssetFinderAsset.AssetType.TERRAIN; if (a.isTerrian) { a.terrainData = AssetDatabase.LoadAssetAtPath(a.asset.assetPath, typeof(Object)) as TerrainData; } a.isSucess = a.asset.ReplaceReference(a.from, a.to, a.toFileId, a.terrainData); if (a.isTerrian) { a.terrainData = null; AssetFinderUnity.UnloadUnusedAssets(); } } isCompleted = false; break; } if (!isCompleted) return; foreach (KeyValuePair item in listReplace) { List lst = item.Value.datas; for (var i = 0; i < lst.Count; i++) { ReplaceData data = lst[i]; if (!data.isUpdated && data.isSucess) { data.isUpdated = true; if (data.isTerrian) { EditorUtility.SetDirty(data.terrainData); AssetDatabase.SaveAssets(); data.terrainData = null; AssetFinderUnity.UnloadUnusedAssets(); } else { try { AssetDatabase.ImportAsset(data.asset.assetPath, ImportAssetOptions.Default); } catch (Exception e) { AssetFinderLOG.LogWarning(data.asset.assetPath + "\n" + e); } } } } } var guidsRefreshed = new HashSet(); EditorApplication.update -= ApplicationUpdate; foreach (KeyValuePair item in listReplace) { List lst = item.Value.datas; for (var i = 0; i < lst.Count; i++) { ReplaceData data = lst[i]; if (data.isSucess && !guidsRefreshed.Contains(data.asset.guid)) { guidsRefreshed.Add(data.asset.guid); AssetFinderCache.Api.RefreshAsset(data.asset.guid, true); } } } // lstThreads = null; listReplace = null; AssetFinderCache.Api.RefreshSelection(); AssetFinderCache.Api.Check4Work(); AssetDatabase.Refresh(); IsMergeProcessing = false; } //[MenuItem("Assets/AssetFinder/Tools/Fix Model Import Material")] //public static void FixModelImportMaterial(){ // if (Selection.activeObject == null) return; // CreatePrefabReplaceModel((GameObject)Selection.activeObject); //} //[MenuItem("GameObject/FR2/Paste Materials", false, 10)] //public static void PasteMaterials(){ // if (Selection.activeObject == null) return; // var r = Selection.activeGameObject.GetComponent(); // Undo.RecordObject(r, "Replace Materials"); // r.materials = model_materials; // EditorUtility.SetDirty(r); //} //[MenuItem("GameObject/FR2/Copy Materials", false, 10)] //public static void CopyMaterials(){ // if (Selection.activeObject == null) return; // var r = Selection.activeGameObject.GetComponent(); // if (r == null) return; // model_materials = r.sharedMaterials; //} //-------------------------- APIs ---------------------- private static void SelectDependencies(bool includeMe) { List list = AssetFinderCache.Api.FindAssets(AssetFinderUnity.Selection_AssetGUIDs, false); var dict = new Dictionary(); if (includeMe) AddToDict(dict, list.ToArray()); for (var i = 0; i < list.Count; i++) { AddToDict(dict, AssetFinderAsset.FindUsage(list[i]).ToArray()); } Selection.objects = dict.Values.ToArray(); } private static void SelectUsed(bool includeMe) { List list = AssetFinderCache.Api.FindAssets(AssetFinderUnity.Selection_AssetGUIDs, false); var dict = new Dictionary(); if (includeMe) AddToDict(dict, list.ToArray()); for (var i = 0; i < list.Count; i++) { AddToDict(dict, list[i].UsedByMap.Values.ToArray()); } Selection.objects = dict.Values.ToArray(); } //-------------------------- UTILS --------------------- internal static void AddToDict(Dictionary dict, params AssetFinderAsset[] list) { for (var j = 0; j < list.Length; j++) { string guid = list[j].guid; if (!dict.ContainsKey(guid)) { string assetPath = AssetDatabase.GUIDToAssetPath(guid); dict.Add(guid, AssetFinderUnity.LoadAssetAtPath(assetPath)); } } } private static List GetSelectionDependencies() { if (!AssetFinderCache.isReady) { AssetFinderLOG.LogWarning("FR2 cache not yet ready, please open Window > AssetFinderWindow and hit scan project!"); return null; } return AssetFinderCache.FindUsage(AssetFinderUnity.Selection_AssetGUIDs).Select( guid => { string assetPath = AssetDatabase.GUIDToAssetPath(guid); return AssetFinderUnity.LoadAssetAtPath(assetPath); } ).ToList(); } private class ProcessReplaceData { public readonly List datas = new List(); public bool processed; } private class ReplaceData { public AssetFinderAsset asset; public string from; public bool isSucess; public bool isTerrian; public bool isUpdated; public TerrainData terrainData; public string to; public long toFileId; } // AssetDatabase.ImportAsset(oAssetPath, ImportAssetOptions.Default); // importer.importMaterials = false; // var importer = AssetImporter.GetAtPath(oAssetPath) as ModelImporter; // var nModel = AssetDatabase.LoadAssetAtPath(oAssetPath); // // Reimport model with importMaterial = false // var extension = Path.GetExtension(oAssetPath); // model_materials = model.GetComponent().sharedMaterials; // var oGUID = AssetDatabase.AssetPathToGUID(oAssetPath); // var oAssetPath = AssetDatabase.GetAssetPath(model); // if (model == null) return; //{ //static void CreatePrefabReplaceModel(GameObject model) //static Material[] model_materials; // //create prefab from new model // var prefabPath = oAssetPath.Replace(extension, ".prefab"); // var clone = (GameObject)Object.Instantiate(nModel); // clone.GetComponent().sharedMaterials = model_materials; // PrefabUtility.CreatePrefab(prefabPath, clone, ReplacePrefabOptions.ReplaceNameBased); // AssetDatabase.SaveAssets(); // GameObject.DestroyImmediate(clone); //} } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Modules/AssetFinderExport.cs.meta ================================================ fileFormatVersion: 2 guid: 7450fa14644448c4a896cc7247ae1c02 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Modules/AssetFinderSceneCache.cs ================================================ #if UNITY_2018_3_OR_NEWER #define SUPPORT_NESTED_PREFAB #endif using System; using System.Collections.Generic; using System.IO; using System.Linq; using UnityEditor; using UnityEngine; using Object = UnityEngine.Object; #if UNITY_2017_1_OR_NEWER using UnityEditor.SceneManagement; using UnityEngine.SceneManagement; #endif #if SUPPORT_NESTED_PREFAB using UnityEditor.Experimental.SceneManagement; #endif namespace VirtueSky.AssetFinder.Editor { internal class SceneRefInfo : IEquatable { public Component sourceComponent; public Object target; public string propertyPath; public bool isSceneObject; public bool IsBackwardRef => target != null && sourceComponent != null; public Object GetTargetComponent() => target; public GameObject GetGameObjectFromTarget() { if (!target) return null; if (target is GameObject go) return go; if (target is Component comp && comp != null) return comp.gameObject; return null; } public bool Equals(SceneRefInfo other) { if (other == null) return false; return sourceComponent == other.sourceComponent && target == other.target && propertyPath == other.propertyPath; } public override bool Equals(object obj) { return obj is SceneRefInfo other && Equals(other); } public override int GetHashCode() { unchecked { int hash = sourceComponent?.GetHashCode() ?? 0; hash = hash * 31 + (target?.GetHashCode() ?? 0); hash = hash * 31 + (propertyPath?.GetHashCode() ?? 0); return hash; } } } internal enum SceneCacheStatus { None, // Never initialized (default state) Changed, // Needs refresh Scanning, // Currently scanning Ready // Ready for use } [Flags] internal enum SceneChangeFlags { None = 0, SceneReset = 1, // Scene unloaded/reloaded or new scene opened SceneModify = 2, // Objects modified (from Undo system) SceneAdditive = 4, // Prefab stage or multi-scene changes UserRefresh = 8 // User-requested full refresh } internal class AssetFinderSceneCache { private static AssetFinderSceneCache _api; public static Action onReady; private SceneCacheStatus _status = SceneCacheStatus.None; private Dictionary> _cache = new Dictionary>(); private bool _isDirty; private SceneChangeFlags _changeFlags = SceneChangeFlags.None; private readonly HashSet _modifiedInstanceIds = new HashSet(); private bool _autoRefresh; private float _lastDirtyTime; private const float DIRTY_DEBOUNCE_TIME = 0.1f; // 100ms debounce public int current; private List listGO; //public HashSet prefabDependencies = new HashSet(); public Dictionary> prefabDependencies = new Dictionary>(); public int total; public AssetFinderSceneCache() { // Register for Unity hierarchy change events // Note: Multiple events are registered to catch different types of scene changes #if UNITY_2018_1_OR_NEWER EditorApplication.hierarchyChanged -= OnSceneChanged; EditorApplication.hierarchyChanged += OnSceneChanged; #else EditorApplication.hierarchyWindowChanged -= OnSceneChanged; EditorApplication.hierarchyWindowChanged += OnSceneChanged; #endif #if UNITY_2018_2_OR_NEWER EditorSceneManager.activeSceneChangedInEditMode -= OnSceneChanged; EditorSceneManager.activeSceneChangedInEditMode += OnSceneChanged; #endif #if UNITY_2017_1_OR_NEWER SceneManager.activeSceneChanged -= OnSceneChanged; SceneManager.activeSceneChanged += OnSceneChanged; SceneManager.sceneLoaded -= OnSceneChanged; SceneManager.sceneLoaded += OnSceneChanged; Undo.postprocessModifications -= OnModify; Undo.postprocessModifications += OnModify; #endif // Add play mode detection EditorApplication.playModeStateChanged -= OnPlayModeStateChanged; EditorApplication.playModeStateChanged += OnPlayModeStateChanged; // Initialize auto-refresh from settings _autoRefresh = AssetFinderSettingExt.isAutoRefreshEnabled; } public static bool hasCache => _api != null && (_api._status == SceneCacheStatus.Ready || _api._status == SceneCacheStatus.Changed); public static AssetFinderSceneCache Api { get { if (_api != null) return _api; _api = new AssetFinderSceneCache(); return _api; } } public static bool isReady => (_api != null && _api._status == SceneCacheStatus.Ready); public static bool hasInit => (_api != null && _api._status != SceneCacheStatus.None); public SceneCacheStatus Status { get => _status; set => _status = value; } public Dictionary> cache { get { if (_cache == null) RefreshCache(false); return _cache; } } public bool Dirty { get => _isDirty; set => _isDirty = value; } public bool AutoRefresh { get => _autoRefresh; set => _autoRefresh = value; } public void RefreshCache(bool force) { if (EditorApplication.isCompiling || EditorApplication.isUpdating) { AssetFinderLOG.Log($"refreshCache skipped: isCompiling: {EditorApplication.isCompiling} / isUpdating: {EditorApplication.isUpdating}"); SetDirty(); return; } if (_status == SceneCacheStatus.Scanning) { AssetFinderLOG.Log($"refreshCache skipped - already scanning"); return; // Prevent re-entrance } // User refresh always forces full scan if (force || (_changeFlags & SceneChangeFlags.UserRefresh) != 0) { PerformFullRefresh(); return; } if (!_autoRefresh) { #if AssetFinderDEBUG Debug.Log($"refreshCache: skipped - autoRefresh == false (but still dirty)"); #endif _isDirty = true; _status = SceneCacheStatus.Changed; return; } // if (_status == SceneCacheStatus.None || _status == SceneCacheStatus.Changed) // { // Debug.Log($"refreshCache: start scanning"); // } // Check if scan is needed bool needsScan = _isDirty || _cache.Count == 0 || _changeFlags != SceneChangeFlags.None; if (!needsScan) { AssetFinderLOG.Log($"refreshCache: skipped - do not needScan"); _status = SceneCacheStatus.Ready; return; } if ((_changeFlags & SceneChangeFlags.SceneReset) != 0) { PerformFullRefresh(); return; } PerformIncrementalRefresh(); } private void PerformFullRefresh() { _status = SceneCacheStatus.Scanning; _isDirty = false; current = 0; total = 0; _cache = new Dictionary>(); prefabDependencies = new Dictionary>(); _modifiedInstanceIds.Clear(); _changeFlags = SceneChangeFlags.None; List listRootGO = null; #if SUPPORT_NESTED_PREFAB if (PrefabStageUtility.GetCurrentPrefabStage() != null) { GameObject rootPrefab = PrefabStageUtility.GetCurrentPrefabStage().prefabContentsRoot; if (rootPrefab != null) listRootGO = new List { rootPrefab }; } #endif if (listRootGO == null) { listGO = AssetFinderUnity.getAllObjsInCurScene().ToList(); } else { listGO = new List(); foreach (GameObject item in listRootGO) { listGO.AddRange(AssetFinderUnity.getAllChild(item, true)); } } // Set total as work count (objects to scan) and freeze it during scan total = listGO.Count; current = 0; if (total == 0 || total == current) { Dirty = false; _status = SceneCacheStatus.Ready; onReady?.Invoke(); return; } AssetFinderLOG.Log($"Register OnUpdate: {nameof(PerformFullRefresh)}"); EditorApplication.update -= OnUpdate; EditorApplication.update += OnUpdate; } private void PerformIncrementalRefresh() { // AssetFinderLOG.Log("PerformIncrementalRefresh!"); _isDirty = false; _status = SceneCacheStatus.Scanning; current = 0; total = 0; // Clean up invalid cache entries var keysToRemove = new List(); foreach (var kvp in _cache) { if (kvp.Key == null || kvp.Key.gameObject == null) { keysToRemove.Add(kvp.Key); } } foreach (var key in keysToRemove) { _cache.Remove(key); } // Get objects that need scanning (modified + new ones) var currentObjects = new HashSet(); List allObjects; #if SUPPORT_NESTED_PREFAB if (PrefabStageUtility.GetCurrentPrefabStage() != null) { GameObject rootPrefab = PrefabStageUtility.GetCurrentPrefabStage().prefabContentsRoot; allObjects = rootPrefab != null ? AssetFinderUnity.getAllChild(rootPrefab, true).ToList() : new List(); } else #endif { allObjects = AssetFinderUnity.getAllObjsInCurScene().ToList(); } foreach (var go in allObjects) { if (go != null) currentObjects.Add(go.GetInstanceID()); } // Find objects to scan (modified or new) listGO = new List(); foreach (var go in allObjects) { if (go == null) continue; int instanceId = go.GetInstanceID(); bool isModified = _modifiedInstanceIds.Contains(instanceId); bool isNew = !_cache.Keys.Any(comp => comp != null && comp.gameObject != null && comp.gameObject.GetInstanceID() == instanceId); if (isModified || isNew) { listGO.Add(go); } } // Set total as work count (objects to scan) and freeze it during scan total = listGO.Count; current = 0; _modifiedInstanceIds.Clear(); _changeFlags = SceneChangeFlags.None; if (total == 0 || current >= total) { _status = SceneCacheStatus.Ready; if (onReady != null) onReady(); return; } #if AssetFinderDEBUG Debug.Log($"Register OnUpdate: {nameof(PerformIncrementalRefresh)} | {current}/{total}"); #endif EditorApplication.update -= OnUpdate; EditorApplication.update += OnUpdate; Dirty = false; } private void OnUpdate() { if (EditorApplication.isCompiling || EditorApplication.isUpdating) { StopScanning(SceneCacheStatus.None); return; } for (var i = 0; i < 5 * AssetFinderCache.priority; i++) { if (listGO == null || listGO.Count <= 0) break; var index = listGO.Count - 1; var go = listGO[index]; if (go == null) { listGO.RemoveAt(index); current++; continue; } // Remove existing cache entries for this GameObject var componentsToRemove = _cache.Keys.Where(comp => comp != null && comp.gameObject == go).ToList(); foreach (var comp in componentsToRemove) { _cache.Remove(comp); } string prefabGUID = AssetFinderUnity.GetPrefabParent(go); if (!string.IsNullOrEmpty(prefabGUID)) { Transform parent = go.transform.parent; while (parent != null) { GameObject g = parent.gameObject; if (!prefabDependencies.ContainsKey(g)) prefabDependencies.Add(g, new HashSet()); prefabDependencies[g].Add(prefabGUID); parent = parent.parent; } } Component[] components = go.GetComponents(); foreach (Component com in components) { if (com == null) continue; var serialized = new SerializedObject(com); SerializedProperty it = serialized.GetIterator().Copy(); while (it.Next(true)) { if (it.propertyType != SerializedPropertyType.ObjectReference) continue; if (it.objectReferenceValue == null) continue; bool isSceneObject = it.objectReferenceValue.IsSceneObject(); if (!_cache.ContainsKey(com)) _cache.Add(com, new HashSet()); _cache[com].Add(new HashValue { target = it.objectReferenceValue, isSceneObject = isSceneObject, propertyPath = it.propertyPath }); } } listGO.RemoveAt(index); current++; } if (listGO != null && listGO.Count > 0) return; // to be continue Dirty = false; StopScanning(SceneCacheStatus.Ready); onReady?.Invoke(); } private void OnPlayModeStateChanged(PlayModeStateChange state) { switch (state) { case PlayModeStateChange.EnteredPlayMode: StopScanning(SceneCacheStatus.None); break; case PlayModeStateChange.ExitingPlayMode: SetDirty(); break; case PlayModeStateChange.EnteredEditMode: if (_autoRefresh) { _changeFlags |= SceneChangeFlags.SceneReset; SetDirty(); EditorApplication.delayCall += () => RefreshCache(false); } break; } } private void OnSceneChanged() { // In play mode, avoid unnecessary dirty marking when auto-refresh is disabled if (Application.isPlaying) { // Only mark dirty if auto-refresh is enabled, otherwise it's pointless if (_autoRefresh) { #if AssetFinderDEBUG Debug.LogWarning($"Set dirty: {nameof(OnSceneChanged)} - Play Mode with AutoRefresh"); #endif SetDirty(); } return; } // Check if we're in prefab mode - don't treat prefab mode changes as scene changes #if SUPPORT_NESTED_PREFAB bool isInPrefabMode = PrefabStageUtility.GetCurrentPrefabStage() != null; if (isInPrefabMode) { #if AssetFinderDEBUG Debug.LogWarning($"Set dirty: {nameof(isInPrefabMode)}"); #endif // Properly mark as dirty and update status SetDirty(); _changeFlags |= SceneChangeFlags.SceneAdditive; // Always perform incremental refresh in prefab mode // because the scene/prefab hierarchy has changed PerformIncrementalRefresh(); return; } #endif // Detect if this is a scene unload vs hierarchy change List currentObjects = AssetFinderUnity.getAllObjsInCurScene().ToList(); // If no objects in scene, it's likely a scene unload - just clean cache without refresh if (currentObjects.Count == 0) { _cache.Clear(); prefabDependencies.Clear(); _modifiedInstanceIds.Clear(); _changeFlags = SceneChangeFlags.None; _status = SceneCacheStatus.Ready; _isDirty = false; return; } // Check for new GameObjects (cloning/duplication) var existingIds = new HashSet(); foreach (var comp in _cache.Keys) { if (comp != null && comp.gameObject != null) { existingIds.Add(comp.gameObject.GetInstanceID()); } } bool hasNewObjects = false; foreach (var go in currentObjects) { if (go != null && !existingIds.Contains(go.GetInstanceID())) { hasNewObjects = true; _modifiedInstanceIds.Add(go.GetInstanceID()); } } // Use incremental refresh for new objects, full refresh for major changes if (hasNewObjects && _cache.Count > 0) { _changeFlags |= SceneChangeFlags.SceneModify; } else { _changeFlags |= SceneChangeFlags.SceneAdditive; } SetDirty(); // Only auto-refresh if auto refresh is enabled and not currently scanning if (_autoRefresh && _status != SceneCacheStatus.Scanning) { Api.RefreshCache(false); } } #if UNITY_2017_1_OR_NEWER private UndoPropertyModification[] OnModify(UndoPropertyModification[] modifications) { bool hasRelevantChange = false; for (var i = 0; i < modifications.Length; i++) { var mod = modifications[i]; // Only mark dirty for object reference changes in scene objects if (mod.currentValue.objectReference != null || mod.previousValue.objectReference != null) { var target = mod.currentValue.target ?? mod.previousValue.target; if (target != null && !EditorUtility.IsPersistent(target)) { hasRelevantChange = true; _modifiedInstanceIds.Add(target.GetInstanceID()); // Also mark the GameObject if target is a component if (target is Component comp && comp.gameObject != null) { _modifiedInstanceIds.Add(comp.gameObject.GetInstanceID()); } } } } if (hasRelevantChange) { _changeFlags |= SceneChangeFlags.SceneModify; SetDirty(); } return modifications; } #endif public void SetDirty() { // Debounce rapid SetDirty calls to prevent unnecessary dirty marking float currentTime = Time.realtimeSinceStartup; if (currentTime - _lastDirtyTime < DIRTY_DEBOUNCE_TIME && _isDirty) { return; // Skip if already dirty and within debounce time } _lastDirtyTime = currentTime; if (_status == SceneCacheStatus.None || _status == SceneCacheStatus.Ready) { _status = SceneCacheStatus.Changed; } _isDirty = true; } public void ForceRefresh() { _changeFlags |= SceneChangeFlags.UserRefresh; SetDirty(); RefreshCache(true); } private void StopScanning(SceneCacheStatus updatedStatus) { // Debug.Log($"StopScanning: {current} / {total} | {_status}"); EditorApplication.update -= OnUpdate; _status = updatedStatus; listGO = null; current = 0; total = 0; } public static Dictionary FindSceneUseSceneObjects(GameObject[] targets) { var results = new Dictionary(); foreach (var selectedGO in targets) { if (selectedGO == null || selectedGO.IsAssetObject()) continue; var key = selectedGO.GetInstanceID().ToString(); if (!results.ContainsKey(key)) { results.Add(key, new AssetFinderSceneRef(0, selectedGO)); } ScanForwardReferences(selectedGO, results); } return results; } public static Dictionary FindSceneBackwardReferences(GameObject[] targets) { var results = new Dictionary(); foreach (var selectedGO in targets) { if (selectedGO.IsAssetObject()) continue; var key = selectedGO.GetInstanceID().ToString(); if (!results.ContainsKey(key)) { results.Add(key, new AssetFinderSceneRef(0, selectedGO)); } } ScanBackwardReferences(targets.Where(t => t != null).ToHashSet(), results); return results; } public static Dictionary FindSceneInScene(GameObject[] targets) { var results = new Dictionary(); foreach (var obj in targets) { if (obj == null || obj.IsAssetObject()) continue; var key = obj.GetInstanceID().ToString(); if (!results.ContainsKey(key)) results.Add(key, new AssetFinderSceneRef(0, obj)); } ScanSceneInScene(targets, results); return results; } private static void ScanForwardReferences(GameObject selectedGO, Dictionary results) { if (selectedGO == null) return; var sceneCache = Api.cache; var components = selectedGO.GetComponents(); for (var i = 0; i < components.Length; i++) { var com = components[i]; if (com == null || com is Transform) continue; if (!sceneCache.TryGetValue(com, out var hashValues)) continue; foreach (var hashValue in hashValues) { if (hashValue.target == null || !hashValue.isSceneObject) continue; var targetGO = GetGameObjectFromTarget(hashValue.target); if (targetGO == null || targetGO == selectedGO) continue; var targetKey = hashValue.target.GetInstanceID().ToString(); if (!results.ContainsKey(targetKey)) { var tRef = new AssetFinderSceneRef(1, hashValue.target) { sourceRefs = new List() }; results.Add(targetKey, tRef); } var targetRef = results[targetKey] as AssetFinderSceneRef; targetRef.sourceRefs.Add(new SceneRefInfo { sourceComponent = com, target = hashValue.target, propertyPath = hashValue.propertyPath, isSceneObject = hashValue.isSceneObject }); } } } private static void ScanBackwardReferences(HashSet selectedGameObjects, Dictionary results) { var sceneCache = Api.cache; foreach (var cacheEntry in sceneCache) { var sourceComponent = cacheEntry.Key; if (sourceComponent == null || sourceComponent.gameObject == null || typeof(Transform).IsAssignableFrom(sourceComponent.GetType())) continue; var sourceGO = sourceComponent.gameObject; if (sourceGO == null || selectedGameObjects.Contains(sourceGO)) continue; foreach (var hashValue in cacheEntry.Value) { if (hashValue.target == null || !hashValue.isSceneObject) continue; var targetGO = GetGameObjectFromTarget(hashValue.target); if (targetGO == null || targetGO == sourceGO || !selectedGameObjects.Contains(targetGO)) continue; var sourceKey = sourceGO.GetInstanceID().ToString(); if (!results.ContainsKey(sourceKey)) { var sourceRef = new AssetFinderSceneRef(1, sourceGO); sourceRef.backwardRefs = new List(); results.Add(sourceKey, sourceRef); } var backwardRef = results[sourceKey] as AssetFinderSceneRef; backwardRef.backwardRefs.Add(new SceneRefInfo { sourceComponent = sourceComponent, target = hashValue.target, propertyPath = hashValue.propertyPath, isSceneObject = hashValue.isSceneObject }); } } } private static void ScanSceneInScene(GameObject[] objs, Dictionary results) { var sceneCache = Api.cache; foreach (var cacheEntry in sceneCache) { var sourceComponent = cacheEntry.Key; if (sourceComponent == null || sourceComponent.gameObject == null || typeof(Transform).IsAssignableFrom(sourceComponent.GetType())) continue; foreach (var hashValue in cacheEntry.Value) { if (hashValue.target == null) continue; var targetGO = GetGameObjectFromTarget(hashValue.target); if (targetGO == null || sourceComponent.gameObject == targetGO) continue; foreach (var obj in objs) { if (obj == null || targetGO != obj) continue; var key = sourceComponent.GetInstanceID().ToString(); if (!results.ContainsKey(key)) { var sourceRef = new AssetFinderSceneRef(1, sourceComponent) { backwardRefs = new List() }; results.Add(key, sourceRef); } var backwardRef = results[key] as AssetFinderSceneRef; backwardRef.backwardRefs.Add(new SceneRefInfo { sourceComponent = sourceComponent, target = hashValue.target, propertyPath = hashValue.propertyPath, isSceneObject = hashValue.isSceneObject }); break; } } } } private static GameObject GetGameObjectFromTarget(Object target) { if (!target) return null; if (target is GameObject go) return go; if (target is Component comp && comp) return comp.gameObject; return null; } internal class HashValue : IEquatable { // original fields – DO NOT RENAME public bool isSceneObject; public Object target; public string propertyPath; // --------- value equality --------- public bool Equals(HashValue other) { if (ReferenceEquals(other, null)) return false; if (ReferenceEquals(this, other)) return true; return isSceneObject == other.isSceneObject && target == other.target && // Unity overloads == propertyPath == other.propertyPath; } public override bool Equals(object obj) => Equals(obj as HashValue); public override int GetHashCode() { unchecked { int hash = 17; hash = hash * 23 + isSceneObject.GetHashCode(); hash = hash * 23 + (target ? target.GetInstanceID() : 0); hash = hash * 23 + (propertyPath?.GetHashCode() ?? 0); return hash; } } public static bool operator ==(HashValue a, HashValue b) => Equals(a, b); public static bool operator !=(HashValue a, HashValue b) => !Equals(a, b); } #if UNITY_2017_1_OR_NEWER private void OnSceneChanged(Scene scene, LoadSceneMode mode) { OnSceneChanged(); } private void OnSceneChanged(Scene arg0, Scene arg1) { OnSceneChanged(); } #endif } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Modules/AssetFinderSceneCache.cs.meta ================================================ fileFormatVersion: 2 guid: 9207f99b6216de54299cf88ed80e86a3 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Modules/AssetFinderSelection.cs ================================================ using System; using System.Collections.Generic; using UnityEditor; using UnityEngine; using UnityObject = UnityEngine.Object; namespace VirtueSky.AssetFinder.Editor { internal class AssetFinderSelection : IRefDraw { internal readonly AssetFinderRefDrawer drawer; internal readonly HashSet guidSet = new HashSet(); internal readonly HashSet instSet = new HashSet(); // Do not reference directly to SceneObject (which might be destroyed anytime) // ------------ instance private bool dirty; internal bool isLock; internal Dictionary refs; public AssetFinderSelection(IWindow window, Func getSortMode, Func getGroupMode) { this.window = window; drawer = new AssetFinderRefDrawer(new AssetFinderRefDrawer.AssetDrawingConfig { window = window, getSortMode = getSortMode, getGroupMode = getGroupMode, showFullPath = false, showFileSize = false, showExtension = true, showUsageType = false, showAssetBundleName = false, showAtlasName = false, showToggle = false, shouldShowExtension = () => true, // Selection panel always shows extensions shouldShowDetailButton = () => false, // Selection panel never shows detail buttons onCacheInvalidated = () => { } // Selection panel doesn't need cache invalidation }) { groupDrawer = { hideGroupIfPossible = true }, level0Group = string.Empty, paddingLeft = -16f }; dirty = true; drawer.SetDirty(); } public int Count => guidSet.Count + instSet.Count; public bool isSelectingAsset => guidSet.Count > 0 && instSet.Count == 0; public bool isSelectingSceneObject => instSet.Count > 0 && guidSet.Count == 0; public IWindow window { get; set; } public int ElementCount() { return refs?.Count ?? 0; } public bool DrawLayout() { if (dirty) RefreshView(); return drawer.DrawLayout(); } public bool Draw(Rect rect) { if (dirty) RefreshView(); if (refs == null) return false; rect.yMax -= 16f; return drawer.Draw(rect); } public void Add(UnityObject sceneObject) { if (sceneObject == null) return; var id = sceneObject.GetInstanceID().ToString(); instSet.Add(id); dirty = true; } public void Add(string guid) { if (guidSet.Contains(guid)) return; string assetPath = AssetDatabase.GUIDToAssetPath(guid); if (string.IsNullOrEmpty(assetPath)) { AssetFinderLOG.LogWarning("Invalid GUID: " + guid); return; } guidSet.Add(guid); dirty = true; } public void AddRange(params string[] guids) { foreach (string id in guids) { Add(id); } dirty = true; } public void Remove(UnityObject sceneObject) { if (sceneObject == null) return; var id = sceneObject.GetInstanceID().ToString(); instSet.Remove(id); dirty = true; } public void Remove(string guidOrInstID) { guidSet.Remove(guidOrInstID); instSet.Remove(guidOrInstID); dirty = true; } public void Clear() { guidSet.Clear(); instSet.Clear(); dirty = true; } public void Add(AssetFinderRef rf) { if (rf.isSceneRef) { Add(rf.component); } else { Add(rf.asset.guid); } } public void Remove(AssetFinderRef rf) { if (rf.isSceneRef) { Remove(rf.component); } else { Remove(rf.asset.guid); } } public void SetDirty() { drawer.SetDirty(); } public event Action OnSelectionChanged; public void SyncFromGlobalSelection() { var manager = AssetFinderSelectionManager.Instance; Clear(); // Copy from global selection to local selection if (manager.IsSelectingSceneObjects) { foreach (var go in manager.SceneSelection.GameObjects) { if (go != null) Add(go); } } else if (manager.IsSelectingAssets) { foreach (var entry in manager.AssetSelection.AssetEntries) { Add(entry.guid); } } dirty = true; } public UnityObject[] GetUnityObjects() { var result = new System.Collections.Generic.List(); // Add scene objects from local selection foreach (string instIdStr in instSet) { if (int.TryParse(instIdStr, out int instId)) { var obj = EditorUtility.InstanceIDToObject(instId); if (obj != null) result.Add(obj); } } // Add asset objects from local selection foreach (string guid in guidSet) { string assetPath = AssetDatabase.GUIDToAssetPath(guid); if (!string.IsNullOrEmpty(assetPath)) { var obj = AssetDatabase.LoadAssetAtPath(assetPath); if (obj != null) result.Add(obj); } } return result.ToArray(); } public void SetUnityObjects(UnityObject[] objects) { Clear(); if (objects != null) { foreach (var obj in objects) { if (obj == null) continue; if (obj.IsSceneObject()) { Add(obj); } else { string assetPath = AssetDatabase.GetAssetPath(obj); if (!string.IsNullOrEmpty(assetPath)) { string guid = AssetDatabase.AssetPathToGUID(assetPath); if (!string.IsNullOrEmpty(guid)) { Add(guid); } } } } } dirty = true; // Trigger refresh after manually setting selection OnSelectionChanged?.Invoke(); } public void RefreshView() { if (refs == null) refs = new Dictionary(); refs.Clear(); if (instSet.Count > 0) { foreach (string instId in instSet) { refs.Add(instId, new AssetFinderSceneRef(0, EditorUtility.InstanceIDToObject(int.Parse(instId)))); } } else { foreach (string guid in guidSet) { AssetFinderAsset asset = AssetFinderCache.Api.Get(guid); refs.Add(guid, new AssetFinderRef(0, 0, asset, null) { isSceneRef = false }); } } drawer.SetRefs(refs); dirty = false; } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Modules/AssetFinderSelection.cs.meta ================================================ fileFormatVersion: 2 guid: f060e78650ad24e4d9f1d569a68bd676 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Modules/Lightmap/AssetFinderLightmap.EnlightenRendererInformation.cs ================================================ using System; using UnityEngine; using Object = UnityEngine.Object; namespace VirtueSky.AssetFinder.Editor { internal static partial class AssetFinderLightmap { [Serializable] private struct EnlightenRendererInformation { public Object renderer; public Vector4 dynamicLightmapSTInSystem; public int systemId; public Hash128 instanceHash; public Hash128 geometryHash; } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Modules/Lightmap/AssetFinderLightmap.EnlightenRendererInformation.cs.meta ================================================ fileFormatVersion: 2 guid: 4882851dfb7a7034587c4d1089108d9a MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Modules/Lightmap/AssetFinderLightmap.EnlightenSceneMapping.cs ================================================ using System; using UnityEngine; namespace VirtueSky.AssetFinder.Editor { internal static partial class AssetFinderLightmap { [Serializable] private sealed class EnlightenSceneMapping { [SerializeField] private EnlightenRendererInformation[] m_Renderers; [SerializeField] private EnlightenSystemInformation[] m_Systems; [SerializeField] private Hash128[] m_Probesets; [SerializeField] private EnlightenSystemAtlasInformation[] m_SystemAtlases; [SerializeField] private EnlightenTerrainChunksInformation[] m_TerrainChunks; public EnlightenRendererInformation[] renderers { get => m_Renderers; set => m_Renderers = value; } public EnlightenSystemInformation[] systems { get => m_Systems; set => m_Systems = value; } public Hash128[] probesets { get => m_Probesets; set => m_Probesets = value; } public EnlightenSystemAtlasInformation[] systemAtlases { get => m_SystemAtlases; set => m_SystemAtlases = value; } public EnlightenTerrainChunksInformation[] terrainChunks { get => m_TerrainChunks; set => m_TerrainChunks = value; } } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Modules/Lightmap/AssetFinderLightmap.EnlightenSceneMapping.cs.meta ================================================ fileFormatVersion: 2 guid: 53fb54741d26bda46aebb9440e0636ae MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Modules/Lightmap/AssetFinderLightmap.EnlightenSystemAtlasInformation.cs ================================================ using System; using UnityEngine; namespace VirtueSky.AssetFinder.Editor { internal static partial class AssetFinderLightmap { [Serializable] private struct EnlightenSystemAtlasInformation { public int atlasSize; public Hash128 atlasHash; public int firstSystemId; } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Modules/Lightmap/AssetFinderLightmap.EnlightenSystemAtlasInformation.cs.meta ================================================ fileFormatVersion: 2 guid: 5083c33ffcca383488fda513a64e8794 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Modules/Lightmap/AssetFinderLightmap.EnlightenSystemInformation.cs ================================================ using System; using UnityEngine; namespace VirtueSky.AssetFinder.Editor { internal static partial class AssetFinderLightmap { [Serializable] private struct EnlightenSystemInformation { public int rendererIndex; public int rendererSize; public int atlasIndex; public int atlasOffsetX; public int atlasOffsetY; public Hash128 inputSystemHash; public Hash128 radiositySystemHash; } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Modules/Lightmap/AssetFinderLightmap.EnlightenSystemInformation.cs.meta ================================================ fileFormatVersion: 2 guid: fb6bd2f4c5d7a0a4182b2a45867d2c7a MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Modules/Lightmap/AssetFinderLightmap.EnlightenTerrainChunksInformation.cs ================================================ using System; namespace VirtueSky.AssetFinder.Editor { internal static partial class AssetFinderLightmap { [Serializable] private struct EnlightenTerrainChunksInformation { public int firstSystemId; public int numChunksInX; public int numChunksInY; } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Modules/Lightmap/AssetFinderLightmap.EnlightenTerrainChunksInformation.cs.meta ================================================ fileFormatVersion: 2 guid: ce351963a678fcd4c88cef2fd06e353b MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Modules/Lightmap/AssetFinderLightmap.LightBakingOutput.cs ================================================ using System; using UnityEngine; namespace VirtueSky.AssetFinder.Editor { internal static partial class AssetFinderLightmap { [Serializable] private struct LightBakingOutput { public int serializedVersion; public int probeOcclusionLightIndex; public int occlusionMaskChannel; public LightmapBakeMode lightmapBakeMode; public bool isBaked; [Serializable] public struct LightmapBakeMode { public LightmapBakeType lightmapBakeType; public MixedLightingMode mixedLightingMode; } } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Modules/Lightmap/AssetFinderLightmap.LightBakingOutput.cs.meta ================================================ fileFormatVersion: 2 guid: 2510794c594290744aecc37a3c152570 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Modules/Lightmap/AssetFinderLightmap.LightingDataAssetRoot.cs ================================================ using System; using UnityEditor; using UnityEngine; using UnityEngine.Rendering; namespace VirtueSky.AssetFinder.Editor { internal static partial class AssetFinderLightmap { [Serializable] private sealed class LightingDataAssetRoot { public SerializedData LightingDataAsset; [Serializable] public struct SerializedData { public int serializedVersion; public SceneAsset m_Scene; public LightmapData[] m_Lightmaps; public Texture2D[] m_AOTextures; public string[] m_LightmapsCacheFiles; public LightProbes m_LightProbes; public int m_LightmapsMode; public SphericalHarmonicsL2 m_BakedAmbientProbeInLinear; public RendererData[] m_LightmappedRendererData; public SceneObjectIdentifier[] m_LightmappedRendererDataIDs; public EnlightenSceneMapping m_EnlightenSceneMapping; public SceneObjectIdentifier[] m_EnlightenSceneMappingRendererIDs; public SceneObjectIdentifier[] m_Lights; public LightBakingOutput[] m_LightBakingOutputs; public string[] m_BakedReflectionProbeCubemapCacheFiles; public Texture[] m_BakedReflectionProbeCubemaps; public SceneObjectIdentifier[] m_BakedReflectionProbes; public byte[] m_EnlightenData; public int m_EnlightenDataVersion; } } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Modules/Lightmap/AssetFinderLightmap.LightingDataAssetRoot.cs.meta ================================================ fileFormatVersion: 2 guid: cd480560ce5931e4192adf9c234df09f MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Modules/Lightmap/AssetFinderLightmap.LightmapData.cs ================================================ using System; using UnityEngine; namespace VirtueSky.AssetFinder.Editor { internal static partial class AssetFinderLightmap { [Serializable] private struct LightmapData { [SerializeField] private Texture2D m_Lightmap; [SerializeField] private Texture2D m_DirLightmap; [SerializeField] private Texture2D m_ShadowMask; public Texture2D lightmap { get => m_Lightmap; set => m_Lightmap = value; } public Texture2D dirLightmap { get => m_DirLightmap; set => m_DirLightmap = value; } public Texture2D shadowMask { get => m_ShadowMask; set => m_ShadowMask = value; } } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Modules/Lightmap/AssetFinderLightmap.LightmapData.cs.meta ================================================ fileFormatVersion: 2 guid: 4199aa256da348d40b1ed01a2b54c60d MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Modules/Lightmap/AssetFinderLightmap.RendererData.cs ================================================ using System; using UnityEngine; namespace VirtueSky.AssetFinder.Editor { internal static partial class AssetFinderLightmap { [Serializable] private struct RendererData { public Mesh uvMesh; public Vector4 terrainDynamicUVST; public Vector4 terrainChunkDynamicUVST; public Vector4 lightmapST; public Vector4 lightmapSTDynamic; public ushort lightmapIndex; public ushort lightmapIndexDynamic; public Hash128 explicitProbeSetHash; } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Modules/Lightmap/AssetFinderLightmap.RendererData.cs.meta ================================================ fileFormatVersion: 2 guid: 0117d519295b4fa4da351c0103d00cdb MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Modules/Lightmap/AssetFinderLightmap.SceneObjectIdentifier.cs ================================================ using System; using UnityEditor; namespace VirtueSky.AssetFinder.Editor { internal static partial class AssetFinderLightmap { [Serializable] private struct SceneObjectIdentifier : IEquatable { public long targetObject; public long targetPrefab; public SceneObjectIdentifier(GlobalObjectId id) { if (id.identifierType != 2) throw new ArgumentException("GlobalObjectId must refer to a scene object.", nameof(id)); targetObject = unchecked((long)id.targetObjectId); targetPrefab = unchecked((long)id.targetPrefabId); } public bool Equals(SceneObjectIdentifier other) { return (targetObject == other.targetObject) && (targetPrefab == other.targetPrefab); } // public GlobalObjectId ToGlobalObjectId(SceneAsset scene) // { // return ToGlobalObjectId(AssetDatabase.GUIDFromAssetPath(AssetDatabase.GetAssetPath(scene))); // } // // public GlobalObjectId ToGlobalObjectId(Scene scene) // { // return ToGlobalObjectId(AssetDatabase.GUIDFromAssetPath(scene.path)); // } // // public GlobalObjectId ToGlobalObjectId(GUID sceneGuid) // { // GlobalObjectId id; // GlobalObjectId.TryParse($"GlobalObjectId_V1-2-{sceneGuid}-{unchecked((ulong)targetObject)}-{unchecked((ulong)targetPrefab)}", out id); // return id; // } // // public static Object SceneObjectIdentifierToObjectSlow(SceneAsset scene, SceneObjectIdentifier id) // { // return SceneObjectIdentifierToObjectSlow(AssetDatabase.GUIDFromAssetPath(AssetDatabase.GetAssetPath(scene)), id); // } // // public static Object SceneObjectIdentifierToObjectSlow(Scene scene, SceneObjectIdentifier id) // { // return SceneObjectIdentifierToObjectSlow(AssetDatabase.GUIDFromAssetPath(scene.path), id); // } // // public static Object SceneObjectIdentifierToObjectSlow(GUID sceneGuid, SceneObjectIdentifier id) // { // return GlobalObjectId.GlobalObjectIdentifierToObjectSlow(id.ToGlobalObjectId(sceneGuid)); // } // // public static void SceneObjectIdentifiersToObjectsSlow(SceneAsset scene, SceneObjectIdentifier[] identifiers, Object[] outputObjects) // { // SceneObjectIdentifiersToObjectsSlow(AssetDatabase.GUIDFromAssetPath(AssetDatabase.GetAssetPath(scene)), identifiers, outputObjects); // } // // public static void SceneObjectIdentifiersToObjectsSlow(Scene scene, SceneObjectIdentifier[] identifiers, Object[] outputObjects) // { // SceneObjectIdentifiersToObjectsSlow(AssetDatabase.GUIDFromAssetPath(scene.path), identifiers, outputObjects); // } // public static void SceneObjectIdentifiersToObjectsSlow(GUID sceneGuid, SceneObjectIdentifier[] identifiers, Object[] outputObjects) // { // var globalIdentifiers = new GlobalObjectId[identifiers.Length]; // // for (int i = 0; i < identifiers.Length; i++) // globalIdentifiers[i] = identifiers[i].ToGlobalObjectId(sceneGuid); // // GlobalObjectId.GlobalObjectIdentifiersToObjectsSlow(globalIdentifiers, outputObjects); // } // // public static void GetSceneObjectIdentifiersSlow(Object[] objects, SceneObjectIdentifier[] outputIdentifiers) // { // var globalIdentifiers = new GlobalObjectId[outputIdentifiers.Length]; // GlobalObjectId.GetGlobalObjectIdsSlow(objects, globalIdentifiers); // // for (int i = 0; i < outputIdentifiers.Length; i++) // { // outputIdentifiers[i] = new SceneObjectIdentifier(globalIdentifiers[i]); // } // } } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Modules/Lightmap/AssetFinderLightmap.SceneObjectIdentifier.cs.meta ================================================ fileFormatVersion: 2 guid: 3b7c7436785d2c04aac3b9aefa0aba9e MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Modules/Lightmap/AssetFinderLightmap.cs ================================================ // CREDITS: // https://github.com/NewBloodInteractive/com.newblood.lighting-internals/tree/master // using System.Collections.Generic; using UnityEditor; using UnityEngine; namespace VirtueSky.AssetFinder.Editor { internal static partial class AssetFinderLightmap { public static IEnumerable Read(LightingDataAsset source) { string json = EditorJsonUtility.ToJson(source); var result = new LightingDataAssetRoot(); EditorJsonUtility.FromJsonOverwrite(json, result); foreach (LightmapData item in result.LightingDataAsset.m_Lightmaps) { if (item.lightmap != null) yield return item.lightmap; if (item.dirLightmap != null) yield return item.dirLightmap; if (item.shadowMask != null) yield return item.shadowMask; } foreach (Texture2D item in result.LightingDataAsset.m_AOTextures) { if (item != null) yield return item; } foreach (Texture item in result.LightingDataAsset.m_BakedReflectionProbeCubemaps) { if (item != null) yield return item; } } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Modules/Lightmap/AssetFinderLightmap.cs.meta ================================================ fileFormatVersion: 2 guid: 4ef2874116395ab4fac519172fee4b55 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Modules/Lightmap.meta ================================================ fileFormatVersion: 2 guid: c696eb171b5a447892765b00918930bf timeCreated: 1746366352 ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Modules.meta ================================================ fileFormatVersion: 2 guid: f93164c19bf346c0b7e1c7ed69192524 timeCreated: 1746366271 ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Monitor/AssetFinderCacheHelper.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using UnityEditor; using UnityEngine; namespace VirtueSky.AssetFinder.Editor { [InitializeOnLoad] internal class AssetFinderCacheHelper : AssetPostprocessor { [NonSerialized] private static HashSet scenes; [NonSerialized] private static HashSet guidsIgnore; [NonSerialized] internal static bool inited = false; static AssetFinderCacheHelper() { try { EditorApplication.update -= InitHelper; EditorApplication.update += InitHelper; } catch (Exception e) { AssetFinderLOG.LogWarning(e); } } private static void OnPostprocessAllAssets( string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths) { if (AssetFinderSettingExt.disable) return; if (EditorApplication.isPlayingOrWillChangePlaymode) return; if (!AssetFinderSettingExt.isAutoRefreshEnabled) return; // OFF mode: do nothing //Debug.Log("OnPostProcessAllAssets : " + ":" + importedAssets.Length + ":" + deletedAssets.Length + ":" + movedAssets.Length + ":" + movedFromAssetPaths.Length); if (!AssetFinderCache.isReady) { AssetFinderLOG.Log($"Not ready, will refresh anyway {importedAssets.Length} !\n{string.Join("\n", importedAssets)}"); return; } // FR2 not yet ready if (AssetFinderCache.Api.AssetMap == null) return; AssetFinderCache.DelayCheck4Changes(); // Handle new/changed assets based on current processing state bool shouldInterruptUsedByBuild = false; for (var i = 0; i < importedAssets.Length; i++) { if (importedAssets[i] == AssetFinderCache.CachePath) continue; string guid = AssetDatabase.AssetPathToGUID(importedAssets[i]); if (!AssetFinderAsset.IsValidGUID(guid)) continue; if (AssetFinderCache.Api.AssetMap.ContainsKey(guid)) { // Get the asset to check if it's critical var asset = AssetFinderCache.Api.Get(guid); if (asset != null && !asset.IsCriticalAsset()) { // Skip marking non-critical assets as dirty AssetFinderLOG.Log($"Skipping non-critical asset change: {importedAssets[i]}"); continue; } // Asset already exists - mark as dirty for re-processing AssetFinderCache.Api.RefreshAsset(guid, true); AssetFinderLOG.Log("Changed : " + importedAssets[i]); // If we're building usedBy map, we need to interrupt and restart from content reading if (AssetFinderCache.Api.currentState == ProcessingState.BuildingUsedBy) { shouldInterruptUsedByBuild = true; } continue; } // New asset - add to AssetMap and queue for processing AssetFinderCache.Api.AddAsset(guid); AssetFinderLOG.Log("New : " + importedAssets[i]); // If we're building usedBy map, we need to interrupt and restart from content reading if (AssetFinderCache.Api.currentState == ProcessingState.BuildingUsedBy) { shouldInterruptUsedByBuild = true; } } for (var i = 0; i < deletedAssets.Length; i++) { string guid = AssetDatabase.AssetPathToGUID(deletedAssets[i]); if (AssetFinderSettingExt.isAutoRefreshEnabled) { AssetFinderCache.Api.RemoveAsset(guid); } AssetFinderLOG.Log("Deleted : " + deletedAssets[i]); } for (var i = 0; i < movedAssets.Length; i++) { string guid = AssetDatabase.AssetPathToGUID(movedAssets[i]); AssetFinderAsset asset = AssetFinderCache.Api.Get(guid); if (asset != null && asset.IsCriticalAsset()) { // Only mark critical assets as dirty when moved asset.MarkAsDirty(); } } // Handle interruption if we were building usedBy and new assets were added if (AssetFinderSettingExt.isAutoRefreshEnabled && shouldInterruptUsedByBuild) { AssetFinderLOG.Log("FR2: Interrupting usedBy build due to new assets, restarting from content reading"); // Reset state to allow restart from content reading phase AssetFinderCache.Api.currentState = ProcessingState.Idle; // Force a complete refresh to restart from content reading AssetFinderCache.Api.IncrementalRefresh(); return; } if (AssetFinderSettingExt.isAutoRefreshEnabled) { AssetFinderLOG.Log("Changes :: " + importedAssets.Length + "/" + AssetFinderCache.Api.workCount); AssetFinderCache.Api.Check4Work(); } } internal static void InitHelper() { if (AssetFinderUnity.isEditorCompiling || AssetFinderUnity.isEditorUpdating) return; if (!AssetFinderCache.isReady) return; EditorApplication.update -= InitHelper; inited = true; InitListScene(); InitIgnore(); CheckGitStatus(false); #if UNITY_2018_1_OR_NEWER EditorBuildSettings.sceneListChanged -= InitListScene; EditorBuildSettings.sceneListChanged += InitListScene; #endif #if UNITY_2022_1_OR_NEWER EditorApplication.projectWindowItemInstanceOnGUI -= OnGUIProjectInstance; EditorApplication.projectWindowItemInstanceOnGUI += OnGUIProjectInstance; #else EditorApplication.projectWindowItemOnGUI -= OnGUIProjectItem; EditorApplication.projectWindowItemOnGUI += OnGUIProjectItem; #endif InitIgnore(); // force repaint all project panels EditorApplication.RepaintProjectWindow(); } private static void CheckGitStatus(bool force) { if (AssetFinderSettingExt.gitIgnoreAdded && !force) return; AssetFinderSettingExt.isGitProject = AssetFinderGitUtil.IsGitProject(); if (!AssetFinderSettingExt.isGitProject) return; AssetFinderSettingExt.gitIgnoreAdded = AssetFinderGitUtil.CheckGitIgnoreContainsFR2Cache(); } public static void InitIgnore() { guidsIgnore = new HashSet(); foreach (string item in AssetFinderSetting.IgnoreAsset) { string guid = AssetDatabase.AssetPathToGUID(item); guidsIgnore.Add(guid); } // Debug.Log($"Init Ignore: {guidsIgnore.Count} items"); } private static void InitListScene() { scenes = new HashSet(); // string[] scenes = new string[sceneCount]; foreach (EditorBuildSettingsScene scene in EditorBuildSettings.scenes) { string sce = AssetDatabase.AssetPathToGUID(scene.path); scenes.Add(sce); } } private static string lastGUID; private static readonly Dictionary _countContentCache = new Dictionary(); private static GUIContent _plusContent; private static void OnGUIProjectInstance(int instanceID, Rect selectionRect) { if (!AssetDatabase.TryGetGUIDAndLocalFileIdentifier(instanceID, out string guid, out long localId)) return; bool isMainAsset = guid != lastGUID; lastGUID = guid; if (isMainAsset) { DrawProjectItem(guid, selectionRect); return; } if (!AssetFinderCache.Api.setting.showSubAssetFileId) return; var rect2 = selectionRect; // Cache the localId GUIContent to avoid repeated creation if (!_countContentCache.TryGetValue((int)localId, out GUIContent label)) { label = new GUIContent(localId.ToString()); _countContentCache[(int)localId] = label; } rect2.xMin = rect2.xMax - EditorStyles.miniLabel.CalcSize(label).x; var c = GUI.color; GUI.color = new Color(.5f, .5f, .5f, 0.5f); GUI.Label(rect2, label, EditorStyles.miniLabel); GUI.color = c; } private static void OnGUIProjectItem(string guid, Rect rect) { bool isMainAsset = guid != lastGUID; lastGUID = guid; if (isMainAsset) DrawProjectItem(guid, rect); } private static void DrawProjectItem(string guid, Rect rect) { var r = new Rect(rect.x, rect.y, 1f, 16f); if (scenes.Contains(guid)) EditorGUI.DrawRect(r, GUI2.Theme(new Color32(72, 150, 191, 255), Color.blue)); else if (guidsIgnore.Contains(guid)) { var ignoreRect = new Rect(rect.x + 3f, rect.y + 6f, 2f, 2f); EditorGUI.DrawRect(ignoreRect, GUI2.darkRed); } if (!AssetFinderCache.isReady) return; // not ready if (!AssetFinderSetting.ShowReferenceCount) return; AssetFinderCache api = AssetFinderCache.Api; if (AssetFinderCache.Api.AssetMap == null) AssetFinderCache.Api.Check4Changes(false); if (!api.AssetMap.TryGetValue(guid, out AssetFinderAsset item)) return; if (item == null || item.UsedByMap == null) return; if (item.UsedByMap.Count > 0) { // Cache GUIContent to avoid allocation int count = item.UsedByMap.Count; if (!_countContentCache.TryGetValue(count, out GUIContent content)) { content = AssetFinderGUIContent.FromString(count.ToString()); _countContentCache[count] = content; } r.width = 0f; r.xMin -= 100f; GUI.Label(r, content, GUI2.miniLabelAlignRight); } else if (item.forcedIncludedInBuild) { var c = GUI.color; GUI.color = c.Alpha(0.2f); // Cache plus content if (_plusContent == null) _plusContent = AssetFinderGUIContent.FromString("+"); r.width = 0f; r.xMin -= 100f; GUI.Label(r, _plusContent, GUI2.miniLabelAlignRight); GUI.color = c; } // CRITICAL FIX: Show warning indicator when auto refresh is off and cache might be stale // Only show for assets that might have reference count issues if (!AssetFinderSettingExt.isAutoRefreshEnabled && api.workCount > 0) { var warningRect = new Rect(rect.xMax - 8f, rect.y + 1f, 6f, 6f); Color oldColor = GUI.color; GUI.color = Color.yellow; EditorGUI.DrawRect(warningRect, Color.yellow); GUI.color = oldColor; // Tooltip to explain the warning if (warningRect.Contains(Event.current.mousePosition)) { GUI.Label(new Rect(Event.current.mousePosition.x, Event.current.mousePosition.y, 200f, 40f), new GUIContent("Auto refresh is disabled. Reference counts may be outdated. Use Window > Find Reference 2 to force refresh.")); } } } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Monitor/AssetFinderCacheHelper.cs.meta ================================================ fileFormatVersion: 2 guid: 64bfab0751586794ca327787084e5533 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Monitor.meta ================================================ fileFormatVersion: 2 guid: 07b0445a569d44558e573b4457f34c6b timeCreated: 1746366842 ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/TreeUI/AssetFinderRef.cs ================================================ using System.Collections.Generic; using UnityEditor; using UnityEngine; using Object = UnityEngine.Object; namespace VirtueSky.AssetFinder.Editor { internal class AssetFinderRef { public AssetFinderAsset addBy; // Callback delegates for advanced bookmark operations (set by the drawer) public System.Action OnCtrlClick; public System.Action OnAltClick; public System.Action OnShiftClick; public AssetFinderAsset asset; public Object component; public int depth; public string group; public int index; public bool isSceneRef; public int matchingScore; public int type; public AssetFinderRef() { } public AssetFinderRef(int index, int depth, AssetFinderAsset asset, AssetFinderAsset by) { this.index = index; this.depth = depth; this.asset = asset; if (asset != null) type = AssetFinderAssetGroupDrawer.GetIndex(asset.extension); addBy = by; // isSceneRef = false; } public AssetFinderRef(int index, int depth, AssetFinderAsset asset, AssetFinderAsset by, string group) : this(index, depth, asset, by) { this.group = group; // isSceneRef = false; } private static int CSVSorter(AssetFinderRef item1, AssetFinderRef item2) { int r = item1.depth.CompareTo(item2.depth); if (r != 0) return r; int t = item1.type.CompareTo(item2.type); if (t != 0) return t; return item1.index.CompareTo(item2.index); } public static AssetFinderRef[] FromDict(Dictionary dict) { if (dict == null || dict.Count == 0) return null; var result = new List(); foreach (KeyValuePair kvp in dict) { if (kvp.Value == null) continue; if (kvp.Value.asset == null) continue; result.Add(kvp.Value); } result.Sort(CSVSorter); return result.ToArray(); } public static AssetFinderRef[] FromList(List list) { if (list == null || list.Count == 0) return null; list.Sort(CSVSorter); var result = new List(); for (var i = 0; i < list.Count; i++) { if (list[i].asset == null) continue; result.Add(list[i]); } return result.ToArray(); } public override string ToString() { if (isSceneRef) { var sr = (AssetFinderSceneRef)this; return sr.scenePath; } return asset.assetPath; } public string GetSceneObjId() { if (component == null) return string.Empty; return component.GetInstanceID().ToString(); } public virtual bool isSelected() { return AssetFinderBookmark.Contains(asset.guid); } public virtual void DrawToogleSelect(Rect r) { bool s = isSelected(); r.width = 16f; Event evt = Event.current; bool isMouseOver = r.Contains(evt.mousePosition); bool isMouseDown = evt.type == EventType.MouseDown && evt.button == 0 && isMouseOver; // Handle modifier keys for advanced selection if (isMouseDown) { bool ctrl = Application.platform == RuntimePlatform.OSXEditor ? evt.command : evt.control; bool alt = evt.alt; bool shift = evt.shift; if (shift) { // Shift+click: Toggle all items in all groups OnShiftClick?.Invoke(this); evt.Use(); return; } else if (alt) { // Alt+click: Toggle all siblings in the same group OnAltClick?.Invoke(this); evt.Use(); return; } else if (ctrl) { // Cmd+click (Mac) / Ctrl+click (PC): Toggle self and set all siblings to the same new state OnCtrlClick?.Invoke(this); evt.Use(); return; } } // Normal toggle behavior if (!GUI2.Toggle(r, ref s)) return; if (s) { AssetFinderBookmark.Add(this); } else { AssetFinderBookmark.Remove(this); } } // Removed - now handled via instance callbacks // Removed - now handled via instance callbacks // Removed - now handled via instance callbacks // Removed - now handled via instance callbacks // public AssetFinderRef(int depth, UnityEngine.Object target) // { // this.component = target; // this.depth = depth; // // isSceneRef = true; // } internal List Append(Dictionary dict, params string[] guidList) { var result = new List(); if (!AssetFinderCache.isReady) { AssetFinderLOG.LogWarning("Cache not yet ready! Please wait!"); return result; } // var excludePackage = !AssetFinderCache.Api.setting.showPackageAsset; //filter to remove items that already in dictionary for (var i = 0; i < guidList.Length; i++) { string guid = guidList[i]; if (dict.ContainsKey(guid)) continue; AssetFinderAsset child = AssetFinderCache.Api.Get(guid); if (child == null) continue; // if (excludePackage && child.inPackages) continue; var r = new AssetFinderRef(dict.Count, depth + 1, child, asset); dict.Add(guid, r); result.Add(r); } return result; } internal void AppendUsedBy(Dictionary result, bool deep) { // var list = Append(result, AssetFinderAsset.FindUsedByGUIDs(asset).ToArray()); // if (!deep) return; // // Add next-level // for (var i = 0;i < list.Count;i ++) // { // list[i].AppendUsedBy(result, true); // } Dictionary h = asset.UsedByMap; List list = deep ? new List() : null; if (asset.UsedByMap == null) return; // bool excludePackage = !AssetFinderCache.Api.setting.showPackageAsset; foreach (KeyValuePair kvp in h) { string guid = kvp.Key; if (result.ContainsKey(guid)) continue; AssetFinderAsset child = AssetFinderCache.Api.Get(guid); if (child == null) continue; if (child.IsMissing) continue; // if (excludePackage && child.inPackages) continue; var r = new AssetFinderRef(result.Count, depth + 1, child, asset); result.Add(guid, r); if (deep) list.Add(r); } if (!deep) return; foreach (AssetFinderRef item in list) { item.AppendUsedBy(result, true); } } internal void AppendUsage(Dictionary result, bool deep) { Dictionary> h = asset.UseGUIDs; List list = deep ? new List() : null; // bool excludePackage = !AssetFinderCache.Api.setting.showPackageAsset; foreach (KeyValuePair> kvp in h) { string guid = kvp.Key; if (result.ContainsKey(guid)) continue; AssetFinderAsset child = AssetFinderCache.Api.Get(guid); if (child == null) continue; if (child.IsMissing) continue; // if (excludePackage && child.inPackages) continue; var r = new AssetFinderRef(result.Count, depth + 1, child, asset); result.Add(guid, r); if (deep) list.Add(r); } if (!deep) return; foreach (AssetFinderRef item in list) { item.AppendUsage(result, true); } } // --------------------- STATIC UTILS ----------------------- internal static Dictionary FindRefs(string[] guids, bool usageOrUsedBy, bool addFolder) { var dict = new Dictionary(); var list = new List(); var selectedGuids = new HashSet(guids); // bool excludePackage = !AssetFinderCache.Api.setting.showPackageAsset; for (var i = 0; i < guids.Length; i++) { string guid = guids[i]; if (dict.ContainsKey(guid)) continue; AssetFinderAsset asset = AssetFinderCache.Api.Get(guid); if (asset == null) continue; // if (excludePackage && asset.inPackages) continue; var r = new AssetFinderRef(i, 0, asset, null); if (!asset.IsFolder || addFolder) dict.Add(guid, r); list.Add(r); } for (var i = 0; i < list.Count; i++) { if (usageOrUsedBy) { list[i].AppendUsage(dict, true); } else { list[i].AppendUsedBy(dict, true); } } // Remove selected objects themselves from results (depth 0) var filteredDict = new Dictionary(); foreach (KeyValuePair kvp in dict) { if (kvp.Value.depth == 0) continue; // Exclude selected objects if (selectedGuids.Contains(kvp.Key)) continue; // Double-check exclusion filteredDict.Add(kvp.Key, kvp.Value); } return filteredDict; } public static Dictionary FindUsage(string[] guids) { return FindRefs(guids, true, true); } public static Dictionary FindUsedBy(string[] guids) { return FindRefs(guids, false, true); } public static Dictionary FindUsageScene(GameObject[] objs, bool depth) { var dict = new Dictionary(); // var list = new List(); for (var i = 0; i < objs.Length; i++) { if (objs[i].IsAssetObject()) continue; //only get in scene //add selection if (!dict.ContainsKey(objs[i].GetInstanceID().ToString())) dict.Add(objs[i].GetInstanceID().ToString(), new AssetFinderSceneRef(0, objs[i])); foreach (Object item in AssetFinderUnity.GetAllRefObjects(objs[i])) { AppendUsageScene(dict, item); } if (!depth) continue; foreach (GameObject child in AssetFinderUnity.getAllChild(objs[i])) { foreach (Object item2 in AssetFinderUnity.GetAllRefObjects(child)) { AppendUsageScene(dict, item2); } } } return dict; } private static void AppendUsageScene(Dictionary dict, Object obj) { string path = AssetDatabase.GetAssetPath(obj); if (string.IsNullOrEmpty(path)) return; string guid = AssetDatabase.AssetPathToGUID(path); if (string.IsNullOrEmpty(guid)) return; if (dict.ContainsKey(guid)) return; AssetFinderAsset asset = AssetFinderCache.Api.Get(guid); if (asset == null) return; // if (!AssetFinderCache.Api.setting.showPackageAsset && asset.inPackages) return; var r = new AssetFinderRef(0, 1, asset, null); dict.Add(guid, r); } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/TreeUI/AssetFinderRef.cs.meta ================================================ fileFormatVersion: 2 guid: 113e4d596d4ef334eb917e73db9d3bca MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/TreeUI/AssetFinderRefDrawer.Mode.cs ================================================ namespace VirtueSky.AssetFinder.Editor { internal partial class AssetFinderRefDrawer { public enum Mode { Dependency, Depth, Type, Extension, Folder, Atlas, AssetBundle, None } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/TreeUI/AssetFinderRefDrawer.Mode.cs.meta ================================================ fileFormatVersion: 2 guid: f9f137444bf56a849a40f847a7f4bfef MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/TreeUI/AssetFinderRefDrawer.Sort.cs ================================================ namespace VirtueSky.AssetFinder.Editor { internal partial class AssetFinderRefDrawer { public enum Sort { Type, Path, Size } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/TreeUI/AssetFinderRefDrawer.Sort.cs.meta ================================================ fileFormatVersion: 2 guid: 670354b3bb8b6ea4bb8aba114885a29b MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/TreeUI/AssetFinderRefDrawer.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using UnityEditor; using UnityEngine; using UnityObject = UnityEngine.Object; namespace VirtueSky.AssetFinder.Editor { internal partial class AssetFinderRefDrawer : IRefDraw { internal class RefDrawerConfig { public IWindow window; public Func getSortMode; public Func getGroupMode; public bool showFullPath; public bool showToggle = true; public bool showHighlight = true; public Func shouldShowExtension; public Func shouldShowDetailButton; public Action onCacheInvalidated; } internal class AssetDrawingConfig : RefDrawerConfig { public bool showFileSize; public bool showExtension; public bool showUsageType; public bool showAssetBundleName; public bool showAtlasName; } internal class SceneDrawingConfig : RefDrawerConfig { public bool showDetails; } public static GUIStyle toolbarSearchField; public static GUIStyle toolbarSearchFieldCancelButton; public static GUIStyle toolbarSearchFieldCancelButtonEmpty; private readonly Dictionary gBookmarkCache = new Dictionary(); private readonly Func getGroupMode; private readonly Func getSortMode; internal readonly AssetFinderTreeUI2.GroupDrawer groupDrawer; public readonly List highlight = new List(); // FILTERING private readonly string searchTerm = string.Empty; private readonly bool showSearch = true; public Action afterItemDraw; public Action beforeItemDraw; public bool caseSensitive = false; public Action customDrawGroupLabel; public Func customGetGroup; // STATUS private bool dirty; public RefDrawerConfig Config { get; private set; } private int excludeCount; public AssetDrawingConfig AssetConfig { get; private set; } public SceneDrawingConfig SceneConfig { get; private set; } public string level0Group; internal List list; public string messageEmpty = "It's empty!"; public string messageNoRefs = "Do select something!"; internal Dictionary refs; private bool selectFilter; public bool showDetail; private bool showIgnore; public float paddingLeft = -4f; public float paddingRight = 0f; // Track whether we have a valid selection (independent of refs count) private bool hasValidSelection = false; // Hook for getting contextual empty message from external source (e.g. window) public Func GetContextualEmptyMessage; public AssetFinderRefDrawer(RefDrawerConfig config) { this.window = config.window; this.getSortMode = config.getSortMode; this.getGroupMode = config.getGroupMode; this.Config = config; this.AssetConfig = config as AssetDrawingConfig ?? new AssetDrawingConfig(); this.SceneConfig = config as SceneDrawingConfig ?? new SceneDrawingConfig(); groupDrawer = new AssetFinderTreeUI2.GroupDrawer(DrawGroup, DrawAsset); } // ORIGINAL internal AssetFinderRef[] source => AssetFinderRef.FromList(list); public IWindow window { get; set; } public bool IsDirty => dirty; public bool Draw(Rect rect) { if (refs == null || refs.Count == 0) { // Show appropriate message based on whether we have a valid selection string message = hasValidSelection ? (GetContextualEmptyMessage?.Invoke() ?? messageEmpty) : messageNoRefs; DrawEmpty(rect, message); return false; } if (dirty || list == null) ApplyFilter(); rect.xMin += paddingLeft; rect.xMax += paddingRight; if (!groupDrawer.hasChildren) { DrawEmpty(rect, GetContextualEmptyMessage?.Invoke() ?? messageEmpty); } else { groupDrawer.Draw(rect); } return false; } public bool DrawLayout() { if (refs == null || refs.Count == 0) { // Only return false if we have no valid selection, otherwise continue to show empty message return !hasValidSelection; } if (dirty || list == null) ApplyFilter(); if (groupDrawer.tree != null) { groupDrawer.tree.itemPaddingLeft = paddingLeft; groupDrawer.tree.itemPaddingRight = paddingRight; } groupDrawer.DrawLayout(); return false; } public int ElementCount() { if (refs == null) return 0; return refs.Count; // return refs.Where(x => x.Value.depth != 0).Count(); } private void DrawEmpty(Rect rect, string text) { rect = GUI2.Padding(rect, 2f, 2f); rect.height = 45f; // Determine message type based on message content MessageType messageType = MessageType.Info; if (text.Contains("not scanned") || text.Contains("content changed") || text.Contains("refresh cache")) { messageType = MessageType.Warning; } EditorGUI.HelpBox(rect, text, messageType); } public void SetRefs(Dictionary dictRefs) { ValidateRefs(dictRefs); refs = dictRefs; SetupRefCallbacks(); // When setting refs directly, we consider this a valid selection hasValidSelection = true; dirty = true; } private void SetupRefCallbacks() { // Setup callbacks for each ref to point to this drawer if (refs != null) { foreach (var kvp in refs) { var rf = kvp.Value; rf.OnCtrlClick = HandleRefCtrlClick; rf.OnAltClick = HandleRefAltClick; rf.OnShiftClick = HandleRefShiftClick; } } } void ValidateRefs(Dictionary dictRefs) { var sceneRef = 0; var assetRef = 0; foreach (var kvp in dictRefs) { if (kvp.Value.isSceneRef) sceneRef++; if (!kvp.Value.isSceneRef) assetRef++; if (sceneRef > 0 && assetRef > 0) { AssetFinderLOG.LogWarning("Mixed content???"); } } } private void SetBookmarkGroup(string groupLabel, bool willbookmark) { string[] ids = groupDrawer.GetChildren(groupLabel); if (ids == null) return; // Handle case where group doesn't exist in groupDict for (var i = 0; i < ids.Length; i++) { AssetFinderRef rf; if (!refs.TryGetValue(ids[i], out rf)) continue; if (willbookmark) { AssetFinderBookmark.Add(rf); } else { AssetFinderBookmark.Remove(rf); } } // Invalidate cache so group toggles reflect the correct state InvalidateGroupCache(); } private BookmarkInfo GetBMInfo(string groupLabel) { BookmarkInfo info = null; if (!gBookmarkCache.TryGetValue(groupLabel, out info)) { string[] ids = groupDrawer.GetChildren(groupLabel); info = new BookmarkInfo(); if (ids != null) { for (var i = 0; i < ids.Length; i++) { AssetFinderRef rf; if (!refs.TryGetValue(ids[i], out rf)) continue; info.total++; bool isBM = AssetFinderBookmark.Contains(rf); if (isBM) info.count++; } } gBookmarkCache.Add(groupLabel, info); } return info; } private void DrawToggleGroup(Rect r, string groupLabel) { BookmarkInfo info = GetBMInfo(groupLabel); bool selectAll = info.count == info.total; r.width = 16f; if (GUI2.Toggle(r, ref selectAll)) SetBookmarkGroup(groupLabel, selectAll); if (!selectAll && (info.count > 0)) { //GUI.DrawTexture(r, EditorStyles. } } private void DrawGroup(Rect r, string label, int childCount) { if (string.IsNullOrEmpty(label)) label = "(none)"; DrawToggleGroup(r, label); r.xMin += 18f; Mode groupMode = getGroupMode(); if (groupMode == Mode.Folder) { Texture tex = AssetDatabase.GetCachedIcon("Assets"); GUI.DrawTexture(new Rect(r.x, r.y, 16f, 16f), tex); r.xMin += 16f; } if (customDrawGroupLabel != null) { customDrawGroupLabel.Invoke(r, label, childCount); } else { GUIContent lbContent = AssetFinderGUIContent.FromString(label); GUI.Label(r, lbContent, EditorStyles.label); Rect cRect = r; cRect.x += EditorStyles.label.CalcSize(lbContent).x; cRect.y += 1f; GUI.Label(cRect, AssetFinderGUIContent.FromString($"({childCount})"), EditorStyles.miniLabel); } bool hasMouse = (Event.current.type == EventType.MouseUp) && r.Contains(Event.current.mousePosition); if (hasMouse && (Event.current.button == 1)) { var menu = new GenericMenu(); menu.AddItem(AssetFinderGUIContent.FromString("Add Bookmark"), false, () => { SetBookmarkGroup(label, true); }); menu.AddItem(AssetFinderGUIContent.FromString("Remove Bookmark"), false, () => { SetBookmarkGroup(label, false); }); menu.ShowAsContext(); Event.current.Use(); } } public void DrawDetails(Rect rect) { Rect r = rect; r.xMin += 18f; r.height = 18f; for (var i = 0; i < highlight.Count; i++) { highlight[i].Draw( r, new AssetFinderAsset.AssetFinderAssetDrawConfig( false, false, false, false, false, false, window, false ) ); r.y += 18f; r.xMin += 18f; } } private void DrawAsset(Rect r, string guid) { if (!refs.TryGetValue(guid, out AssetFinderRef rf)) return; if (rf.isSceneRef) { if (rf.component == null) return; if (!(rf is AssetFinderSceneRef re)) return; beforeItemDraw?.Invoke(r, rf); if (Config.showToggle) { rf.DrawToogleSelect(r); r.xMin += 32f; } re.Draw(r, getGroupMode(), SceneConfig.showDetails, Config.showFullPath); } else { beforeItemDraw?.Invoke(r, rf); // Draw content first so right-side buttons handle mouse events before the bookmark toggle Rect contentRect = r; if (Config.showToggle) contentRect.xMin += 32f; bool isHighlight = Config.showHighlight && highlight.Contains(rf.asset); // if (isHighlight) // { // var hlRect = new Rect(-20, r.y, 15f, r.height); // GUI2.Rect(hlRect, GUI2.darkGreen); // } // Use configurable delegates for behavior bool shouldShowExtension = Config.shouldShowExtension?.Invoke() ?? AssetConfig.showExtension; bool shouldShowDetailBtn = Config.shouldShowDetailButton?.Invoke() ?? true; Action onShowDetail = () => { showDetail = true; highlight.Clear(); highlight.Add(rf.asset); AssetFinderAsset p = rf.addBy; var cnt = 0; while ((p != null) && refs.ContainsKey(p.guid)) { highlight.Add(p); AssetFinderRef AssetFinderref = refs[p.guid]; if (AssetFinderref != null) p = AssetFinderref.addBy; if (++cnt > 100) { AssetFinderLOG.LogWarning("Break on depth 1000????"); break; } } highlight.Sort((item1, item2) => { int d1 = refs[item1.guid].depth; int d2 = refs[item2.guid].depth; return d1.CompareTo(d2); }); Event.current.Use(); }; rf.asset.Draw( contentRect, new AssetFinderAsset.AssetFinderAssetDrawConfig( isHighlight, Config.showFullPath, AssetConfig.showFileSize, AssetConfig.showAssetBundleName && AssetFinderSetting.s.displayAssetBundleName, AssetConfig.showAtlasName && AssetFinderSetting.s.displayAtlasName, AssetConfig.showUsageType, window, shouldShowExtension, shouldShowDetailBtn ? onShowDetail : null ) ); if (Config.showToggle) { rf.DrawToogleSelect(r); } } afterItemDraw?.Invoke(r, rf); } private string GetGroup(AssetFinderRef rf) { if (customGetGroup != null) return customGetGroup(rf); if (rf.depth == 0) return level0Group; if (getGroupMode() == Mode.None) return "(no group)"; AssetFinderSceneRef sr = null; if (rf.isSceneRef) { sr = rf as AssetFinderSceneRef; if (sr == null) return null; } if (!rf.isSceneRef) { if (rf.asset.IsExcluded) { return null; // "(ignored)" } } switch (getGroupMode()) { case Mode.Extension: { // if (!rf.isSceneRef) Debug.Log($"Extension: {rf.asset.assetPath} | {rf.asset.extension}"); return rf.isSceneRef ? sr.targetType : string.IsNullOrEmpty(rf.asset.extension) ? "(no extension)" : rf.asset.extension; } case Mode.Type: { return rf.isSceneRef ? sr.targetType : AssetFinderAssetGroupDrawer.FILTERS[rf.type].name; } case Mode.Folder: return rf.isSceneRef ? sr.scenePath : rf.asset.assetFolder; case Mode.Dependency: { return rf.depth == 1 ? "Direct Usage" : "Indirect Usage"; } case Mode.Depth: { return "Level " + rf.depth; } case Mode.Atlas: return rf.isSceneRef ? "(not in atlas)" : string.IsNullOrEmpty(rf.asset.AtlasName) ? "(not in atlas)" : rf.asset.AtlasName; case Mode.AssetBundle: return rf.isSceneRef ? "(not in assetbundle)" : string.IsNullOrEmpty(rf.asset.AssetBundleName) ? "(not in assetbundle)" : rf.asset.AssetBundleName; } return "(others)"; } private void SortGroup(List groups) { groups.Sort((item1, item2) => { if (item1.Contains("(")) return 1; if (item2.Contains("(")) return -1; return string.Compare(item1, item2, StringComparison.Ordinal); }); } public AssetFinderRefDrawer Reset(string[] assetGUIDs, bool isUsage) //, bool isSceneRef { gBookmarkCache.Clear(); // Set hasValidSelection based on whether we received valid asset GUIDs hasValidSelection = assetGUIDs != null && assetGUIDs.Length > 0; refs = isUsage ? AssetFinderRef.FindUsage(assetGUIDs) : AssetFinderRef.FindUsedBy(assetGUIDs); SetupRefCallbacks(); // ValidateRefs(dictRefs); dirty = true; if (list != null) list.Clear(); return this; } public void Reset(Dictionary newRefs) { if (refs == null) refs = new Dictionary(); refs.Clear(); ValidateRefs(newRefs); foreach (KeyValuePair kvp in newRefs) { refs.Add(kvp.Key, kvp.Value); } SetupRefCallbacks(); // When resetting with refs directly, we consider this a valid selection hasValidSelection = true; dirty = true; if (list != null) list.Clear(); } public AssetFinderRefDrawer Reset(GameObject[] objs, bool findDept, bool findPrefabInAsset) { // Set hasValidSelection based on whether we received valid GameObjects hasValidSelection = objs != null && objs.Length > 0; refs = AssetFinderRef.FindUsageScene(objs, findDept) .Where(item=> !item.Value.isSceneRef) .ToDictionary(kvp => kvp.Key, kvp => kvp.Value); var guidss = new List(); Dictionary> dependent = AssetFinderSceneCache.Api.prefabDependencies; foreach (GameObject gameObject in objs) { if (!dependent.TryGetValue(gameObject, out HashSet hash)) continue; foreach (string guid in hash) { guidss.Add(guid); } } Dictionary usageRefs1 = AssetFinderRef.FindUsage(guidss.ToArray()); foreach (KeyValuePair kvp in usageRefs1) { if (refs.ContainsKey(kvp.Key)) continue; if (guidss.Contains(kvp.Key)) kvp.Value.depth = 1; refs.Add(kvp.Key, kvp.Value); } if (findPrefabInAsset) { var guids = new List(); for (var i = 0; i < objs.Length; i++) { string guid = AssetFinderUnity.GetPrefabParent(objs[i]); if (string.IsNullOrEmpty(guid)) continue; guids.Add(guid); } Dictionary usageRefs = AssetFinderRef.FindUsage(guids.ToArray()); foreach (KeyValuePair kvp in usageRefs) { if (refs.ContainsKey(kvp.Key)) continue; if (guids.Contains(kvp.Key)) kvp.Value.depth = 1; refs.Add(kvp.Key, kvp.Value); } } SetupRefCallbacks(); dirty = true; if (list != null) list.Clear(); return this; } //ref in scene public AssetFinderRefDrawer Reset(string[] assetGUIDs) { // Set hasValidSelection based on whether we received valid asset GUIDs hasValidSelection = assetGUIDs != null && assetGUIDs.Length > 0; refs = AssetFinderSceneRef.FindRefInScene(assetGUIDs, true, SetRefInScene); SetupRefCallbacks(); dirty = true; if (list != null) list.Clear(); return this; } private void SetRefInScene(Dictionary data) { refs = data; SetupRefCallbacks(); dirty = true; if (list != null) list.Clear(); } //scene in scene public AssetFinderRefDrawer ResetSceneInScene(GameObject[] objs) { // Set hasValidSelection based on whether we received valid GameObjects hasValidSelection = objs != null && objs.Length > 0; refs = AssetFinderSceneRef.FindSceneInScene(objs); SetupRefCallbacks(); dirty = true; if (list != null) list.Clear(); return this; } public AssetFinderRefDrawer ResetSceneUseSceneObjects(GameObject[] objs) { // Set hasValidSelection based on whether we received valid GameObjects hasValidSelection = objs != null && objs.Length > 0; refs = AssetFinderSceneRef.FindSceneUseSceneObjects(objs); SetupRefCallbacks(); dirty = true; if (list != null) list.Clear(); return this; } public AssetFinderRefDrawer ResetUnusedAsset(bool recursive = true) { List lst = AssetFinderCache.Api.ScanUnused(recursive); refs = lst.ToDictionary(x => x.guid, x => new AssetFinderRef(0, 1, x, null)); SetupRefCallbacks(); // For unused assets, we always consider this a valid operation hasValidSelection = true; dirty = true; if (list != null) list.Clear(); return this; } public void RefreshSort() { if (list == null) return; list.RemoveAll(item => item == null || (item.isSceneRef ? (item.component == null) : (item.asset == null) )); if (list.Count == 0) return; list.Sort((r1, r2) => { bool isMixed = r1.isSceneRef != r2.isSceneRef; if (isMixed) { #if AssetFinderDEBUG var sb = new System.Text.StringBuilder(); sb.Append("r1: " + r1.ToString()); sb.AppendLine(); sb.Append("r2: " +r2.ToString()); AssetFinderLOG.LogWarning($"Mixed compared!\n{sb}"); #endif int v1 = r1.isSceneRef ? 1 : 0; int v2 = r2.isSceneRef ? 1 : 0; return v2.CompareTo(v1); } if (r1.isSceneRef) { var rs1 = (AssetFinderSceneRef)r1; var rs2 = (AssetFinderSceneRef)r2; return SortAsset(rs1.sceneFullPath, rs2.sceneFullPath, rs1.targetType, rs2.targetType, getSortMode() == Sort.Path); } if (r1.asset == null) return -1; if (r2.asset == null) return 1; return SortAsset( r1.asset.assetPath, r2.asset.assetPath, r1.asset.extension, r2.asset.extension, false ); }); groupDrawer.Reset(list, rf => { if (rf == null) return null; return rf.isSceneRef ? rf.GetSceneObjId() : rf.asset?.guid; }, GetGroup, SortGroup); } public bool isExclueAnyItem() { return excludeCount > 0; } private void ApplyFilter() { dirty = false; if (refs == null) return; if (list == null) { list = new List(); } else { list.Clear(); } int minScore = searchTerm.Length; string term1 = searchTerm; if (!caseSensitive) term1 = term1.ToLower(); string term2 = term1.Replace(" ", string.Empty); excludeCount = 0; foreach (KeyValuePair item in refs) { AssetFinderRef r = item.Value; if (AssetFinderSetting.IsTypeExcluded(r.type)) { excludeCount++; continue; //skip this one } if (!showSearch || string.IsNullOrEmpty(searchTerm)) { r.matchingScore = 0; list.Add(r); continue; } //calculate matching score string name1 = r.isSceneRef ? (r as AssetFinderSceneRef)?.sceneFullPath : r.asset.assetName; if (!caseSensitive) name1 = name1?.ToLower(); string name2 = name1?.Replace(" ", string.Empty); int score1 = AssetFinderUnity.StringMatch(term1, name1); int score2 = AssetFinderUnity.StringMatch(term2, name2); r.matchingScore = Mathf.Max(score1, score2); if (r.matchingScore > minScore) list.Add(r); } RefreshSort(); } public void SetDirty() { dirty = true; } public void InvalidateGroupCache() { gBookmarkCache.Clear(); Config.onCacheInvalidated?.Invoke(); } public string GetGroupForRef(AssetFinderRef rf) { return GetGroup(rf); } public void ToggleAllItems() { if (refs == null) return; // Determine the new state based on majority rule int bookmarkedCount = 0; int totalCount = 0; foreach (var kvp in refs) { totalCount++; if (AssetFinderBookmark.Contains(kvp.Value)) { bookmarkedCount++; } } bool newState = bookmarkedCount < totalCount / 2; // If less than half are bookmarked, bookmark all foreach (var kvp in refs) { if (newState) { AssetFinderBookmark.Add(kvp.Value); } else { AssetFinderBookmark.Remove(kvp.Value); } } InvalidateGroupCache(); } public void ToggleGroupItems(string groupLabel) { string[] ids = groupDrawer.GetChildren(groupLabel); if (ids == null) return; // Toggle each sibling individually - if it's on, turn it off; if it's off, turn it on for (var i = 0; i < ids.Length; i++) { if (!refs.TryGetValue(ids[i], out AssetFinderRef rf)) continue; if (AssetFinderBookmark.Contains(rf)) { AssetFinderBookmark.Remove(rf); } else { AssetFinderBookmark.Add(rf); } } InvalidateGroupCache(); } public void SetGroupItemsState(string groupLabel, bool willBookmark) { string[] ids = groupDrawer.GetChildren(groupLabel); if (ids == null) return; for (var i = 0; i < ids.Length; i++) { if (!refs.TryGetValue(ids[i], out AssetFinderRef rf)) continue; if (willBookmark) { AssetFinderBookmark.Add(rf); } else { AssetFinderBookmark.Remove(rf); } } } private void HandleRefCtrlClick(AssetFinderRef rf) { // Toggle self and set all siblings to the same new state bool newState = !rf.isSelected(); if (newState) { AssetFinderBookmark.Add(rf); } else { AssetFinderBookmark.Remove(rf); } // Then set all siblings to the same state string groupName = GetGroupForRef(rf); if (!string.IsNullOrEmpty(groupName) && groupDrawer.GetChildren(groupName) != null) { SetGroupItemsState(groupName, newState); } InvalidateGroupCache(); } private void HandleRefAltClick(AssetFinderRef rf) { // Toggle all siblings in the same group string groupName = GetGroupForRef(rf); if (!string.IsNullOrEmpty(groupName) && groupDrawer.GetChildren(groupName) != null) { ToggleGroupItems(groupName); } } private void HandleRefShiftClick(AssetFinderRef rf) { // Toggle all items in all groups ToggleAllItems(); } public void ClearSelection() { hasValidSelection = false; refs = null; if (list != null) list.Clear(); dirty = true; } private int SortAsset(string term11, string term12, string term21, string term22, bool swap) { // if (term11 == null) term11 = string.Empty; // if (term12 == null) term12 = string.Empty; // if (term21 == null) term21 = string.Empty; // if (term22 == null) term22 = string.Empty; int v1 = string.Compare(term11, term12, StringComparison.Ordinal); int v2 = string.Compare(term21, term22, StringComparison.Ordinal); return swap ? v1 == 0 ? v2 : v1 : v2 == 0 ? v1 : v2; } public Dictionary getRefs() { return refs; } internal class BookmarkInfo { public int count; public int total; } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/TreeUI/AssetFinderRefDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: fcd5eb719592c5744b610afe347e2db4 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/TreeUI/AssetFinderSceneRef.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using UnityEditor; using UnityEngine; using UnityObject = UnityEngine.Object; namespace VirtueSky.AssetFinder.Editor { internal class AssetFinderSceneRef : AssetFinderRef { internal static readonly Dictionary CacheType = new Dictionary(); private static Action> onFindRefInSceneComplete; private static Dictionary refs = new Dictionary(); private static string[] cacheAssetGuids; private GUIContent assetNameGC; private GUIContent assetTypeGC; public Func drawFullPath; public string sceneFullPath = ""; public string scenePath = ""; public string targetType; public List sourceRefs; public List backwardRefs; public AssetFinderSceneRef(int index, int depth, AssetFinderAsset asset, AssetFinderAsset by) : base(index, depth, asset, by) { isSceneRef = false; sourceRefs = new List(); backwardRefs = new List(); // Ensure tooltip always shows full path with proper slashes string tooltipPath = asset?.assetPath ?? "Unknown"; assetNameGC = new GUIContent(asset?.assetName ?? "Unknown", tooltipPath); assetTypeGC = new GUIContent(""); } public AssetFinderSceneRef(int depth, UnityObject target) : base(0, depth, null, null) { component = target; this.depth = depth; isSceneRef = true; sourceRefs = new List(); backwardRefs = new List(); InitializeTargetInfo(target); } void InitializeTargetInfo(UnityObject target) { if (target == null) { targetType = "Missing"; scenePath = ""; sceneFullPath = "Missing Object"; assetNameGC = new GUIContent("Missing Object", "Object has been destroyed"); assetTypeGC = new GUIContent("Missing"); return; } if (target is GameObject obj) { targetType = nameof(GameObject); scenePath = AssetFinderUnity.GetGameObjectPath(obj, false); // Add trailing slash if scenePath is not empty string pathWithSlash = string.IsNullOrEmpty(scenePath) ? "" : scenePath + "/"; sceneFullPath = pathWithSlash + obj.name; assetNameGC = new GUIContent(obj.name, sceneFullPath); assetTypeGC = GUIContent.none; } else if (target is Component com) { targetType = component.GetType().Name; scenePath = AssetFinderUnity.GetGameObjectPath(com.gameObject, false); // Add trailing slash if scenePath is not empty string pathWithSlash = string.IsNullOrEmpty(scenePath) ? "" : scenePath + "/"; sceneFullPath = pathWithSlash + com.gameObject.name; assetNameGC = new GUIContent(com.gameObject.name, sceneFullPath); assetTypeGC = new GUIContent(component.GetType().Name); } } public override bool isSelected() { return (component != null) && AssetFinderBookmark.Contains(component); } public void Draw(Rect r, AssetFinderRefDrawer.Mode groupMode, bool showDetails, bool drawFullPath = false) { r.xMin -= 12f; r.xMax -= 12f; var margin = 2; var pingRect = r; Rect iconRect = GUI2.LeftRect(16f, ref r); // Right-click context menu for scene objects if ((Event.current.type == EventType.MouseUp) && (Event.current.button == 1) && pingRect.Contains(Event.current.mousePosition)) { var menu = new GenericMenu(); menu.AddItem(new GUIContent("Open"), false, () => { if (component != null) EditorGUIUtility.PingObject(component); }); menu.AddItem(new GUIContent("Ping"), false, () => { if (component != null) EditorGUIUtility.PingObject(component); }); #if UNITY_2022_3_OR_NEWER menu.AddItem(new GUIContent("Properties..."), false, () => { if (component != null) EditorUtility.OpenPropertyEditor(component); }); #else menu.AddDisabledItem(new GUIContent("Properties...")); #endif menu.ShowAsContext(); Event.current.Use(); } var (icon, iconTooltip) = GetTargetIcon(); // Calculate sizes based on whether we're showing full path float pathW = 0f; float nameW = 0f; if (drawFullPath && !string.IsNullOrEmpty(scenePath)) { pathW = EditorStyles.miniLabel.CalcSize(AssetFinderGUIContent.FromString(scenePath + "/")).x; nameW = EditorStyles.label.CalcSize(assetNameGC).x; } else { nameW = EditorStyles.label.CalcSize(assetNameGC).x; } Rect pathRect = drawFullPath && pathW > 0 ? GUI2.LeftRect(pathW, ref r) : new Rect(); Rect nameRect = GUI2.LeftRect(nameW, ref r); float typeW = EditorStyles.miniLabel.CalcSize(assetTypeGC).x; Rect typeRect = GUI2.LeftRect(typeW + 4f, ref r); pingRect.width = 16f + margin + pathW + nameW + typeW + 4f; DrawPingRect(pingRect); DrawTargetIcon(iconRect, icon, iconTooltip); DrawScenePath(pathRect, drawFullPath); DrawTargetName(nameRect, assetNameGC); DrawTargetType(typeRect, assetTypeGC); #if UNITY_2022_3_OR_NEWER // Draw P only on hover and repaint on mouse move for responsiveness Rect rowRect = new Rect(r.x, r.y, r.width, AssetFinderTheme.Current.TreeItemHeight); bool isHover = rowRect.Contains(Event.current.mousePosition); if (Event.current.type == EventType.MouseMove) { var focused = EditorWindow.focusedWindow; if (focused != null) focused.Repaint(); } if (isHover) { var propRect = new Rect(r.x + r.width - 22f, r.y, 22f, r.height); r.width -= 22f; float miniH = 16f; propRect.y += Mathf.Floor((AssetFinderTheme.Current.TreeItemHeight - miniH) / 2f); propRect.height = miniH; if (GUI.Button(propRect, new GUIContent("P", "Open Properties"), EditorStyles.miniButton)) { if (component != null) EditorUtility.OpenPropertyEditor(component); } } #endif if (AssetFinderSetting.ShowUsedByClassed) { DrawReferenceIcons(r); } } (Texture icon, string tooltip) GetTargetIcon() { if (component == null) return (null, ""); if (component is GameObject go) return (EditorGUIUtility.ObjectContent(go, typeof(GameObject)).image, "GameObject"); if (component is Component comp) return (EditorGUIUtility.ObjectContent(comp, comp.GetType()).image, comp.GetType().Name); return (EditorGUIUtility.ObjectContent(component, component.GetType()).image, component.GetType().Name); } void DrawTargetIcon(Rect iconRect, Texture icon, string iconTooltip) { if (icon != null) { var iconContent = new GUIContent(icon, iconTooltip); GUI.Label(iconRect, iconContent, EditorStyles.label); } } void DrawScenePath(Rect pathRect, bool drawFullPath) { if (!drawFullPath || string.IsNullOrEmpty(scenePath)) return; Color c = GUI.color; GUI.color = new Color(c.r, c.g, c.b, c.a * 0.5f); // Dim the path like Unity's Project panel GUI.Label(pathRect, AssetFinderGUIContent.FromString(scenePath + "/"), EditorStyles.miniLabel); GUI.color = c; } void DrawTargetName(Rect nameRect, GUIContent displayContent) { if (isSelected()) { Color c = GUI.color; GUI.color = GUI.skin.settings.selectionColor; GUI.DrawTexture(nameRect, EditorGUIUtility.whiteTexture); GUI.color = c; } GUI.Label(nameRect, displayContent, EditorStyles.label); } void DrawTargetType(Rect typeRect, GUIContent typeContent) { if (!string.IsNullOrEmpty(typeContent.text)) { // Always dim component type, no hover effects Color c = GUI.color; GUI.color = new Color(c.r, c.g, c.b, c.a * 0.6f); GUI.Label(typeRect, typeContent, EditorStyles.miniLabel); GUI.color = c; } } void DrawReferenceIcons(Rect r) { if (sourceRefs?.Count > 0) { DrawComponentIcons(r, sourceRefs, (refInfo, iconRect) => { EditorGUIUtility.PingObject(refInfo.sourceComponent); AssetFinderUnity.PingAndHighlight(refInfo.sourceComponent, refInfo.propertyPath); GUIUtility.ExitGUI(); }); } else if (backwardRefs?.Count > 0) { DrawComponentIcons(r, backwardRefs, (refInfo, iconRect) => { EditorGUIUtility.PingObject(refInfo.sourceComponent); AssetFinderUnity.PingAndHighlight(refInfo.sourceComponent, refInfo.propertyPath); GUIUtility.ExitGUI(); }); } } void DrawComponentIcons(Rect r, List refInfos, Action onIconClick) { if (refInfos == null || refInfos.Count == 0) return; float width = 18f; float totalWidth = width * refInfos.Count; if (refInfos.Count == 1) { var refInfo = refInfos[0]; var beautifiedPath = BeautifyPropertyPath(refInfo.propertyPath); var labelWidth = EditorStyles.miniLabel.CalcSize(new GUIContent(beautifiedPath)).x; totalWidth += labelWidth + 4f; } float startX = r.x + r.width - totalWidth; for (int i = 0; i < refInfos.Count; i++) { var refInfo = refInfos[i]; var targetComponent = refInfo.GetTargetComponent(); if (targetComponent == null) continue; float currentX = startX; if (refInfos.Count == 1) { var beautifiedPath = BeautifyPropertyPath(refInfo.propertyPath); var labelWidth = EditorStyles.miniLabel.CalcSize(new GUIContent(beautifiedPath)).x; var labelRect = new Rect(currentX, r.y, labelWidth, r.height); // Always dim property path, no hover effects Color c = GUI.color; GUI.color = new Color(c.r, c.g, c.b, c.a * 0.6f); GUI.Label(labelRect, beautifiedPath, EditorStyles.miniLabel); GUI.color = c; currentX += labelWidth + 4f; } else { currentX += i * width; } var iconRect = new Rect(currentX, r.y, width, r.height); var icon = EditorGUIUtility.ObjectContent(targetComponent, targetComponent.GetType()).image; var tooltipText = refInfo.IsBackwardRef ? refInfo.propertyPath : $"{refInfo.sourceComponent.GetType().Name}.{refInfo.propertyPath}"; var content = new GUIContent(icon, tooltipText); GUI.Label(iconRect, content); if (GUI.Button(iconRect, content, EditorStyles.label)) { onIconClick(refInfo, iconRect); } } } string BeautifyPropertyPath(string propertyPath) { if (string.IsNullOrEmpty(propertyPath)) return ""; string result = propertyPath; result = result.Replace(".Array.data[", "["); result = result.Replace("].Array.data[", "]["); return result; } void DrawPingRect(Rect pingRect) { bool selected = isSelected(); if ((Event.current.type == EventType.MouseDown) && (Event.current.button == 0)) { if (pingRect.Contains(Event.current.mousePosition)) { if (Event.current.control || Event.current.command) { if (selected) { AssetFinderBookmark.Remove(this); } else { AssetFinderBookmark.Add(this); } } else { // Set smart lock state for scene ping to allow selection change var fr2Window = EditorWindow.GetWindow(false, null, false); if (fr2Window != null && fr2Window.smartLock != null) { fr2Window.smartLock.SetPingLockState(AssetFinderSmartLock.PingLockState.Scene); } EditorGUIUtility.PingObject(component); } Event.current.Use(); } } } public static Dictionary FindSceneUseSceneObjects(GameObject[] targets) { return AssetFinderSceneCache.FindSceneUseSceneObjects(targets); } public static Dictionary FindSceneBackwardReferences(GameObject[] targets) { return AssetFinderSceneCache.FindSceneBackwardReferences(targets); } public static Dictionary FindSceneInScene(GameObject[] targets) { return AssetFinderSceneCache.FindSceneInScene(targets); } public static Dictionary FindRefInScene( string[] assetGUIDs, bool depth, Action> onComplete) { cacheAssetGuids = assetGUIDs; onFindRefInSceneComplete = onComplete; if (AssetFinderSceneCache.isReady) { FindRefInScene(); } else { AssetFinderSceneCache.onReady -= FindRefInScene; AssetFinderSceneCache.onReady += FindRefInScene; } return refs; } private static void FindRefInScene() { if (refs == null) refs = new Dictionary(); else refs.Clear(); // Reuse existing dictionary for (var i = 0; i < cacheAssetGuids.Length; i++) { AssetFinderAsset asset = AssetFinderCache.Api.Get(cacheAssetGuids[i]); if (asset == null) continue; Add(refs, asset, 0); ApplyFilter(refs, asset); } if (onFindRefInSceneComplete != null) onFindRefInSceneComplete(refs); AssetFinderSceneCache.onReady -= FindRefInScene; } private static void ApplyFilter(Dictionary refs, AssetFinderAsset asset) { string targetPath = AssetDatabase.GUIDToAssetPath(asset.guid); if (string.IsNullOrEmpty(targetPath)) return; if (targetPath != asset.assetPath) asset.MarkAsDirty(); UnityObject target = AssetDatabase.LoadAssetAtPath(targetPath, typeof(UnityObject)); if (target == null) return; if (target is GameObject) { foreach (GameObject item in AssetFinderUnity.getAllObjsInCurScene()) { if (AssetFinderUnity.CheckIsPrefab(item)) { string itemGUID = AssetFinderUnity.GetPrefabParent(item); if (itemGUID == asset.guid) Add(refs, item, 1); } } } // Search through all cached components for references to this asset foreach (var cacheEntry in AssetFinderSceneCache.Api.cache) { foreach (var hashValue in cacheEntry.Value) { if (targetPath == AssetDatabase.GetAssetPath(hashValue.target)) { Add(refs, cacheEntry.Key, 1); break; } } } } private static void Add(Dictionary refs, AssetFinderAsset asset, int depth) { string targetId = asset.guid; if (!refs.ContainsKey(targetId)) refs.Add(targetId, new AssetFinderRef(0, depth, asset, null)); } private static void Add(Dictionary refs, UnityObject target, int depth) { if (target == null) return; var targetId = target.GetInstanceID().ToString(); if (!refs.ContainsKey(targetId)) refs.Add(targetId, new AssetFinderSceneRef(depth, target)); } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/TreeUI/AssetFinderSceneRef.cs.meta ================================================ fileFormatVersion: 2 guid: 22ef8041c6ba839489532b86afe8c941 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/TreeUI/AssetFinderTreeUI2.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using UnityEditor; using UnityEngine; namespace VirtueSky.AssetFinder.Editor { internal class AssetFinderTreeUI2 { internal Drawer drawer; public float itemPaddingRight = 0f; public float itemPaddingLeft = 0f; private Vector2 position; internal TreeItem rootItem; internal Rect visibleRect; public AssetFinderTreeUI2(Drawer drawer) { this.drawer = drawer; } public void Reset(params string[] root) { position = Vector2.zero; rootItem = new TreeItem { tree = this, id = "$root", height = 0, depth = -1, _isOpen = true, highlight = false, childCount = root.Length }; rootItem.RefreshChildren(root); rootItem.DeepOpen(); } public void Draw(Rect rect) { if (rect.width > 0) visibleRect = rect; var contentRect = new Rect(0f, 0f, 1f, rootItem.childrenHeight + AssetFinderTheme.Current.TreeContentPadding * 2); bool noScroll = contentRect.height < visibleRect.height; if (noScroll) position = Vector2.zero; var minY = (int)position.y; var maxY = (int)(position.y + visibleRect.height); contentRect.x -= AssetFinderSetting.TreeIndent; TreeItem.DrawCall = 0; TreeItem.DrawRender = 0; position = GUI.BeginScrollView(visibleRect, position, contentRect); { var theme = AssetFinderTheme.Current; var r = new Rect(theme.TreeContentPadding + itemPaddingLeft, theme.TreeContentPadding, rect.width - (noScroll ? theme.CompactSpacing : theme.ScrollBarWidth) - itemPaddingRight - theme.TreeContentPadding * 2 - itemPaddingLeft, theme.TreeItemHeight); var index = 0; rootItem.Draw(ref index, ref r, minY, maxY); } GUI.EndScrollView(); } public void DrawLayout() { EventType evtType = Event.current.type; var theme = AssetFinderTheme.Current; Rect r = GUILayoutUtility.GetRect(1f, Screen.width, theme.TreeItemHeight, Screen.height); if (evtType != EventType.Layout) visibleRect = r; Draw(visibleRect); } public bool NoScroll() { return rootItem.childrenHeight < visibleRect.height; } // ------------------------ DELEGATE -------------- internal class Drawer { public virtual int GetHeight(string id) { return (int)AssetFinderTheme.Current.TreeItemHeight; } public virtual int GetChildCount(string id) { return 0; } public virtual string[] GetChildren(string id) { return null; } public virtual void Draw(Rect r, TreeItem item) { GUI.Label(r, AssetFinderGUIContent.From(item.id)); } } internal class GroupDrawer : Drawer { public readonly Action drawGroup; public readonly Action drawItem; private Dictionary> groupDict; public bool hideGroupIfPossible; internal AssetFinderTreeUI2 tree; public GroupDrawer(Action drawGroup, Action drawItem) { this.drawItem = drawItem; this.drawGroup = drawGroup; } public bool hasChildren => (tree != null) && (tree.rootItem.childCount > 0); public bool hasValidTree => (groupDict != null) && (tree != null); // ----------------- TREE WRAPPER ------------------ public bool TreeNoScroll() { return tree.NoScroll(); } public void Reset( List items, Func idFunc, Func groupFunc, Action> customGroupSort = null) { groupDict = new Dictionary>(); for (var i = 0; i < items.Count; i++) { List list; string groupName = groupFunc(items[i]); if (groupName == null) continue; // do not exclude groupName string.Empty string itemId = idFunc(items[i]); if (string.IsNullOrEmpty(itemId)) continue; // ignore items without id if (!groupDict.TryGetValue(groupName, out list)) { list = new List(); groupDict.Add(groupName, list); } list.Add(itemId); } if (tree == null) tree = new AssetFinderTreeUI2(this); List groups = groupDict.Keys.ToList(); if (hideGroupIfPossible && (groups.Count == 1)) //single group : Flat list { List v = groupDict[groups[0]]; tree.Reset(v.ToArray()); groupDict.Clear(); } else { //multiple groups if (customGroupSort != null) { customGroupSort(groups); } else { groups.Sort(); } tree.Reset(groups.ToArray()); } } public void Draw(Rect r) { if (tree != null) tree.Draw(r); } public void DrawLayout() { if (tree != null) tree.DrawLayout(); } // ----------------- DRAWER WRAPPER ------------------ public override int GetChildCount(string id) { if (string.IsNullOrEmpty(id) || groupDict == null) return 0; return groupDict.TryGetValue(id, out List group) ? group.Count : 0; } public override string[] GetChildren(string id) { if (groupDict == null) return null; return groupDict.TryGetValue(id, out List group) ? group.ToArray() : null; } public override void Draw(Rect r, TreeItem item) { if (groupDict != null && groupDict.TryGetValue(item.id, out List group)) { drawGroup(r, item.id, item.childCount); return; } drawItem(r, item.id); } } // ------------------------ TreeItem2 -------------- internal class TreeItem { public static int DrawCall; public static int DrawRender; internal bool _isOpen; public int childCount; public List children; public int childrenHeight; public int depth; // item depth public int height; public bool highlight; public string id; // item id internal TreeItem parent; //static Color COLOR = new Color(0f, 0f, 0f, 0.05f); internal AssetFinderTreeUI2 tree; public bool IsOpen { get => _isOpen; set { if (_isOpen == value || childCount == 0) return; _isOpen = value; if (_isOpen) { if (children == null) RefreshChildren(tree.drawer.GetChildren(id)); //Update height for all parents TreeItem p = parent; while (p != null) { p.childrenHeight += childrenHeight; p = p.parent; } } else { //Update height for all parents TreeItem p = parent; while (p != null) { p.childrenHeight -= childrenHeight; p = p.parent; } } } } internal void DeepOpen() { IsOpen = true; if (children == null) return; for (var i = 0; i < children.Count; i++) { children[i].DeepOpen(); } } internal void Draw(ref int index, ref Rect rect, int minY, int maxY) { DrawCall++; float min = rect.y; float max = rect.y + height; bool interMin = (min >= minY) && (min <= maxY); bool interMax = (max >= minY) && (max <= maxY); if ((height > 0) && (interMin || interMax)) { DrawRender++; rect.height = height; if ((index % 2 == 1) && AssetFinderSetting.AlternateRowColor) { Color o = GUI.color; GUI.color = AssetFinderSetting.RowColor; // GUI.DrawTexture(rect, EditorGUIUtility.whiteTexture); GUI.DrawTexture(new Rect(rect.x - AssetFinderSetting.TreeIndent, rect.y, rect.width, rect.height), EditorGUIUtility.whiteTexture); GUI.color = o; } var theme = AssetFinderTheme.Current; float x = (depth + 1) * theme.TreeIndentSize; tree.drawer.Draw(new Rect(x, rect.y, rect.width - x, rect.height), this); if (childCount > 0) { IsOpen = GUI.Toggle(new Rect(rect.x + x - theme.TreeIndentSize, rect.y, theme.TreeToggleSize, theme.TreeToggleSize), IsOpen, GUIContent.none, EditorStyles.foldout); } index++; rect.y += height + theme.TreeItemSpacing; } else { rect.y += height + AssetFinderTheme.Current.TreeItemSpacing; } if (_isOpen && (rect.y <= maxY)) //draw children { for (var i = 0; i < children.Count; i++) { children[i].Draw(ref index, ref rect, minY, maxY); if (rect.y > maxY) break; } } } internal void RefreshChildren(string[] childrenIDs) { childCount = childrenIDs.Length; childrenHeight = 0; children = new List(); for (var i = 0; i < childCount; i++) { string itemId = childrenIDs[i]; var item = new TreeItem { tree = tree, parent = this, id = itemId, depth = depth + 1, highlight = false, height = tree.drawer.GetHeight(itemId), childCount = tree.drawer.GetChildCount(itemId) }; childrenHeight += item.height + (int)AssetFinderTheme.Current.TreeItemSpacing; children.Add(item); } } } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/TreeUI/AssetFinderTreeUI2.cs.meta ================================================ fileFormatVersion: 2 guid: fee07110472e29344bfcab27b4a7725a MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/TreeUI.meta ================================================ fileFormatVersion: 2 guid: eff03ad31a264fe8863d406929204090 timeCreated: 1746366439 ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/UI/AssetFinderDeleteButton.cs ================================================ using System; using UnityEditor; using UnityEngine; namespace VirtueSky.AssetFinder.Editor { internal class AssetFinderDeleteButton { public string confirmMessage; public GUIContent deleteLabel; public bool hasConfirm; public string warningMessage; public bool Draw(Action onConfirmDelete) { GUILayout.BeginHorizontal(); { EditorGUILayout.HelpBox(warningMessage, MessageType.Warning); GUILayout.BeginVertical(); { GUILayout.Space(2f); hasConfirm = GUILayout.Toggle(hasConfirm, confirmMessage); EditorGUI.BeginDisabledGroup(!hasConfirm); { GUI2.BackgroundColor(() => { if (GUILayout.Button(deleteLabel, EditorStyles.miniButton)) { hasConfirm = false; onConfirmDelete(); GUIUtility.ExitGUI(); } }, GUI2.darkRed, 0.8f); } EditorGUI.EndDisabledGroup(); } GUILayout.EndVertical(); } GUILayout.EndHorizontal(); return false; } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/UI/AssetFinderDeleteButton.cs.meta ================================================ fileFormatVersion: 2 guid: 37ca5ee8134e93741a29ac2b528d5096 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/UI/AssetFinderEnumDrawer.cs ================================================ using System; using System.Collections.Generic; using UnityEditor; using UnityEngine; namespace VirtueSky.AssetFinder.Editor { internal class AssetFinderEnumDrawer { [NonSerialized] internal EnumInfo AssetFinderenum; public int index; public string tooltip; public bool DrawLayout(ref T enumValue, params GUILayoutOption[] options) { if (AssetFinderenum == null) { Type enumType = enumValue.GetType(); AssetFinderenum = EnumInfo.Get(enumType); index = AssetFinderenum.IndexOf(enumValue); } if (Event.current.type == EventType.Repaint || Event.current.type == EventType.Layout) { GUILayout.Label(AssetFinderenum.contents[index], EditorStyles.toolbarPopup, options); return false; } int nIndex = EditorGUILayout.Popup(index, AssetFinderenum.contents, EditorStyles.toolbarPopup, options); if (nIndex == index) { // Debug.LogWarning($"Same index: {nIndex} | {index}"); return false; } index = nIndex; enumValue = (T)AssetFinderenum.ValueAt(index); return true; } public bool Draw(Rect rect, ref T enumValue) { if (AssetFinderenum == null) { Type enumType = enumValue.GetType(); AssetFinderenum = EnumInfo.Get(enumType); index = AssetFinderenum.IndexOf(enumValue); } if (Event.current.type == EventType.Layout) return false; if (Event.current.type == EventType.Repaint) { GUIContent content = AssetFinderenum.contents[index]; if (!string.IsNullOrEmpty(tooltip)) content.tooltip = tooltip; GUI.Label(rect, content, EditorStyles.toolbarPopup); return false; } int nIndex = EditorGUI.Popup(rect, index, AssetFinderenum.contents, EditorStyles.toolbarPopup); //, options if (nIndex != index) { index = nIndex; enumValue = (T)AssetFinderenum.ValueAt(index); return true; } return false; } internal class EnumInfo { public static readonly Dictionary cache = new Dictionary(); public readonly GUIContent[] contents; public readonly Array values; public EnumInfo(Type enumType) { string[] names = Enum.GetNames(enumType); values = Enum.GetValues(enumType); contents = new GUIContent[names.Length]; for (var i = 0; i < names.Length; i++) { contents[i] = AssetFinderGUIContent.FromString(names[i]); } } public EnumInfo(params object[] enumValues) { values = enumValues; contents = new GUIContent[values.Length]; for (var i = 0; i < values.Length; i++) { contents[i] = AssetFinderGUIContent.FromString(enumValues[i].ToString()); } } public static EnumInfo Get(Type type) { if (cache.TryGetValue(type, out EnumInfo result)) { return result; } result = new EnumInfo(type); cache.Add(type, result); return result; } public int IndexOf(object enumValue) { return Array.IndexOf(values, enumValue); } public object ValueAt(int index) { return values.GetValue(index); } } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/UI/AssetFinderEnumDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: de6985c1c8c545540b3e3e792b255328 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/UI/AssetFinderGUIContent.cs ================================================ using System; using System.Collections.Generic; using UnityEditor; using UnityEngine; namespace VirtueSky.AssetFinder.Editor { internal static class AssetFinderGUIContent { // Cache to improve performance private static readonly Dictionary stringMap = new Dictionary(); private static readonly Dictionary tooltipMap = new Dictionary(); private static readonly Dictionary intMap = new Dictionary(); private static readonly Dictionary texMap = new Dictionary(); private static readonly Dictionary stringTexMap = new Dictionary(); private static readonly Dictionary typeMap = new Dictionary(); public static void Release() { stringMap.Clear(); texMap.Clear(); } public static GUIContent FromString(string title, string tooltip = null) { if (string.IsNullOrEmpty(title)) { AssetFinderLOG.LogWarning("Title is null or empty!"); return GUIContent.none; } if (stringMap.TryGetValue(title, out GUIContent result)) return result; result = new GUIContent(title, tooltip); stringMap.Add(title, result); return result; } public static GUIContent FromType(Type t, string tooltip = null) { if (typeMap.TryGetValue(t, out GUIContent result)) return result; result = new GUIContent(EditorGUIUtility.ObjectContent(null, t).image, tooltip); typeMap.Add(t, result); return result; } public static GUIContent Tooltip(string tooltip) { if (tooltipMap.TryGetValue(tooltip, out GUIContent result)) return result; result = new GUIContent(string.Empty, tooltip); tooltipMap.Add(tooltip, result); return result; } public static GUIContent From(object data) { if (data is GUIContent content) return content; if (data is Texture texture) return FromTexture(texture); if (data is string s) return FromString(s); if (data is Type t) return FromType(t); return data is int i ? FromInt(i) : GUIContent.none; } public static GUIContent FromInt(int val) { if (intMap.TryGetValue(val, out GUIContent result)) return result; var str = val.ToString(); result = FromString(str); intMap.Add(val, result); return result; } public static GUIContent FromTexture(Texture tex, string tooltip = null) { if (texMap.TryGetValue(tex, out GUIContent result)) return result; result = new GUIContent(tex, tooltip); texMap.Add(tex, result); return result; } public static GUIContent From(string title, Texture tex, string tooltip = null) { if (stringTexMap.TryGetValue(title, out GUIContent result)) return result; result = new GUIContent(title, tex, tooltip); stringTexMap.Add(title, result); return result; } public static GUIContent[] FromArrayLabelIcon(params object[] data) { var result = new List(); for (var i = 0; i < data.Length; i++) { result.Add(From(data[0].ToString(), (Texture)data[1])); } return result.ToArray(); } public static GUIContent[] FromArray(params object[] data) { var result = new List(); foreach (object item in data) { if (item is string s) { result.Add(FromString(s)); continue; } if (item is Texture texture) { result.Add(FromTexture(texture)); continue; } if (item is GUIContent content) { result.Add(content); continue; } AssetFinderLOG.LogWarning("Unsupported type: " + item); } return result.ToArray(); } public static GUIContent[] FromEnum(Type enumType) { Array values = Enum.GetValues(enumType); var result = new List(); foreach (object item in values) { result.Add(FromString(item.ToString())); } return result.ToArray(); } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/UI/AssetFinderGUIContent.cs.meta ================================================ fileFormatVersion: 2 guid: c9c752a5ea34866408787cdd5356b47c MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/UI/AssetFinderIcon.cs ================================================ using System.Reflection; using System.Collections.Generic; using UnityEditor; using UnityEngine; namespace VirtueSky.AssetFinder.Editor { internal static class AssetFinderIcon { public static GUIContent Lock => TryGet("LockIcon-On", "Click to unlock"); public static GUIContent Unlock => TryGet("LockIcon", "Click to lock"); #if UNITY_2019_3_OR_NEWER public static GUIContent Refresh => TryGet("d_Refresh@2x"); #else public static GUIContent Refresh { get { return TryGet("LookDevResetEnv"); } } #endif public static GUIContent Selection => TryGet("d_Selectable Icon"); public static GUIContent Details => TryGet("d_UnityEditor.SceneHierarchyWindow"); public static GUIContent Favorite => TryGet("d_Favorite"); public static GUIContent Setting => TryGet("d_SettingsIcon"); public static GUIContent Ignore => TryGet("ShurikenCheckMarkMixed"); public static GUIContent Plus => TryGet("ShurikenPlus"); public static GUIContent Visibility => TryGet("ClothInspector.ViewValue"); #if UNITY_2019_3_OR_NEWER public static GUIContent Panel => TryGet("VerticalSplit"); #else public static GUIContent Panel { get { return TryGet("d_LookDevSideBySide"); } } #endif public static GUIContent Layout => TryGet("FreeformLayoutGroup Icon"); public static GUIContent Sort => TryGet("AlphabeticalSorting"); //d_DefaultSorting public static GUIContent CustomTool => TryGet("CustomTool", "Advanced Tools"); #if UNITY_2019_3_OR_NEWER public static GUIContent Filter => TryGet("d_ToggleUVOverlay@2x"); #else public static GUIContent Filter { get { return TryGet("LookDevSplit"); } } #endif public static GUIContent Group => TryGet("EditCollider"); public static GUIContent Delete => TryGet("d_TreeEditor.Trash"); public static GUIContent Split => TryGet("VerticalSplit"); public static GUIContent Close => TryGet("LookDevClose"); public static GUIContent Prefab => TryGet("d_Prefab Icon"); public static GUIContent Asset => TryGet("Folder Icon"); public static GUIContent Warning => TryGet("console.warnicon"); public static GUIContent Info => TryGet("console.warnicon"); public static GUIContent Filesize => TryGet("Download-Available@2x", "Show File Size"); public static GUIContent FileExtension => TryGet("d_curvekeyframeweighted", "Show File Extension"); public static GUIContent AssetBundle => TryGet("CloudConnect"); public static GUIContent Script => TryGet("dll Script Icon"); public static GUIContent Material => TryGet("d_TreeEditor.Material"); public static GUIContent Scene => TryGet("UnityLogo"); #if UNITY_2017_1_OR_NEWER public static GUIContent Atlas => TryGet("SpriteAtlas Icon"); #endif public static GUIContent Folder => TryGet("Project"); public static GUIContent FullPath => TryGet("UnityEditor.HierarchyWindow", "Show full asset path"); public static GUIContent Hierarchy => TryGet("UnityEditor.HierarchyWindow"); public static GUIContent Organize => TryGet("FolderEmpty Icon"); private static readonly MethodInfo _loadIconMethod = typeof(EditorGUIUtility) .GetMethod("LoadIcon", BindingFlags.Static | BindingFlags.NonPublic); private static readonly Dictionary _cache = new Dictionary(); private static GUIContent TryGet(string id, string tooltip = null) { if (_cache.TryGetValue(id, out GUIContent result)) return result ?? GUIContent.none; Texture2D tex = null; if (_loadIconMethod != null) tex = _loadIconMethod.Invoke(null, new object[] { id }) as Texture2D; GUIContent icon = tex != null ? new GUIContent(tex) : new GUIContent(Texture2D.whiteTexture); if (!string.IsNullOrEmpty(tooltip)) icon.tooltip = tooltip; _cache.Add(id, icon); return icon; } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/UI/AssetFinderIcon.cs.meta ================================================ fileFormatVersion: 2 guid: b55e5a87ccb7972448444ff9b63a7a24 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/UI/AssetFinderObjectDrawer.cs ================================================ using System.Collections.Generic; using UnityEditor; using UnityEngine; using UnityObject = UnityEngine.Object; namespace VirtueSky.AssetFinder.Editor { internal class AssetFinderObjectDrawer { private static readonly Dictionary contentMap = new Dictionary(); private static GUIStyle objectFieldStyle; public void DrawOnly(Rect rect, UnityObject target) { GUIContent content; if (target == null) { content = AssetFinderGUIContent.From("(none)", AssetPreview.GetMiniTypeThumbnail(typeof(GameObject))); } else if (!contentMap.TryGetValue(target, out content)) { content = AssetFinderGUIContent.From(target.name, AssetPreview.GetMiniTypeThumbnail(target.GetType())); contentMap.Add(target, content); } if (objectFieldStyle == null) { objectFieldStyle = new GUIStyle(EditorStyles.objectField) { margin = new RectOffset(16, 0, 0, 0) }; } EditorGUIUtility.SetIconSize(new Vector2(12f, 12f)); GUI.Label(rect, content, objectFieldStyle); } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/UI/AssetFinderObjectDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: bb7d43676aa6b92438f93faf242e93f1 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/UI/AssetFinderSearchView.cs ================================================ using UnityEditor; using UnityEngine; namespace VirtueSky.AssetFinder.Editor { internal class AssetFinderSearchView { public static GUIStyle toolbarSearchField; public static GUIStyle toolbarSearchFieldCancelButton; public static GUIStyle toolbarSearchFieldCancelButtonEmpty; private bool caseSensitive; private string searchTerm = string.Empty; public static void InitSearchStyle() { toolbarSearchField = "ToolbarSeachTextFieldPopup"; toolbarSearchFieldCancelButton = "ToolbarSeachCancelButton"; toolbarSearchFieldCancelButtonEmpty = "ToolbarSeachCancelButtonEmpty"; } public bool DrawLayout() { var dirty = false; if (toolbarSearchField == null) InitSearchStyle(); GUILayout.BeginHorizontal(EditorStyles.toolbar); { bool v = GUILayout.Toggle(caseSensitive, "Aa", EditorStyles.toolbarButton, GUI2.GLW_24); if (v != caseSensitive) { caseSensitive = v; dirty = true; } GUILayout.Space(2f); string value = GUILayout.TextField(searchTerm, toolbarSearchField, GUI2.GLW_140); if (searchTerm != value) { searchTerm = value; dirty = true; } GUIStyle style = string.IsNullOrEmpty(searchTerm) ? toolbarSearchFieldCancelButtonEmpty : toolbarSearchFieldCancelButton; if (GUILayout.Button("Cancel", style)) { searchTerm = string.Empty; dirty = true; } } GUILayout.EndHorizontal(); return dirty; } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/UI/AssetFinderSearchView.cs.meta ================================================ fileFormatVersion: 2 guid: 2bdaf062f9e6ed74fa4901a9775036d0 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/UI/AssetFinderSplitView.cs ================================================ //#define AssetFinderDEBUG using System; using System.Collections.Generic; using UnityEditor; using UnityEngine; namespace VirtueSky.AssetFinder.Editor { internal class AssetFinderSplitView { private const float SPLIT_SIZE = 2f; private readonly GUILayoutOption[] expandWH = { GUILayout.ExpandWidth(true), GUILayout.ExpandHeight(true) }; private readonly IWindow window; private Rect _rect; private int _visibleCount; private bool dirty; public bool isHorz; private int resizeIndex = -1; public bool hasResize; public List splits = new List(); public AssetFinderSplitView(IWindow w) { window = w; } public bool isVisible => _visibleCount > 0; public void CalculateWeight() { _visibleCount = 0; var _totalWeight = 0f; for (var i = 0; i < splits.Count; i++) { Info info = splits[i]; if (!info.visible) continue; info.stIndex = _visibleCount; _totalWeight += info.weight; _visibleCount++; } if (_visibleCount == 0 || _totalWeight == 0) { Debug.LogWarning("Nothing visible!"); return; } var cWeight = 0f; for (var i = 0; i < splits.Count; i++) { Info info = splits[i]; if (!info.visible) continue; cWeight += info.weight; info.normWeight = info.weight / _totalWeight; } } public void Draw(Rect rect) { if (rect.width > 0 || rect.height > 0) _rect = rect; if (dirty) { dirty = false; CalculateWeight(); } if (resizeIndex == -1) ApplySizePolicies(); float sz = (_visibleCount - 1) * SPLIT_SIZE; float dx = _rect.x; float dy = _rect.y; for (var i = 0; i < splits.Count; i++) { Info info = splits[i]; if (!info.visible) continue; var rr = new Rect ( dx, dy, isHorz ? (_rect.width - sz) * info.normWeight : _rect.width, isHorz ? _rect.height : (_rect.height - sz) * info.normWeight ); if ((rr.width > 0) && (rr.height > 0)) info.rect = rr; if (info.draw != null) info.DoDraw(); if (info.sizePolicy == Info.SizePolicy.KeepPixel && Event.current.type == EventType.Repaint) { float current = isHorz ? rr.width : rr.height; info.preferredPixel = Mathf.Max(info.minPixel, current); } if (info.stIndex < _visibleCount - 1) DrawSpliter(i, isHorz ? info.rect.xMax : info.rect.yMax); if (isHorz) { dx += info.rect.width + SPLIT_SIZE; } else { dy += info.rect.height + SPLIT_SIZE; } } } private void ApplySizePolicies() { int visible = 0; for (int i = 0; i < splits.Count; i++) if (splits[i].visible) visible++; if (visible == 0) return; float totalGaps = (visible - 1) * SPLIT_SIZE; float available = isHorz ? _rect.width : _rect.height; float content = Mathf.Max(0f, available - totalGaps); float fixedPixels = 0f; float flexibleBasis = 0f; for (int i = 0; i < splits.Count; i++) { var sp = splits[i]; if (!sp.visible) continue; if (sp.sizePolicy == Info.SizePolicy.KeepPixel) { float pref = sp.preferredPixel; pref = Mathf.Max(sp.minPixel, pref); fixedPixels += Mathf.Max(0f, pref); } else { flexibleBasis += Mathf.Max(0.0001f, sp.weight); } } float scale = 1f; if (fixedPixels > content && fixedPixels > 0f) scale = content / fixedPixels; float remaining = Mathf.Max(0f, content - Mathf.Min(fixedPixels, content)); for (int i = 0; i < splits.Count; i++) { var sp = splits[i]; if (!sp.visible) continue; if (sp.sizePolicy == Info.SizePolicy.KeepPixel) { float pref = sp.preferredPixel; pref = Mathf.Max(sp.minPixel, pref); sp.weight = Mathf.Max(0f, pref) * scale; } } if (remaining > 0f) { float basis = Mathf.Max(0.0001f, flexibleBasis); for (int i = 0; i < splits.Count; i++) { var sp = splits[i]; if (!sp.visible) continue; if (sp.sizePolicy == Info.SizePolicy.Flexible) { float share = Mathf.Max(0.0001f, sp.weight) / basis; sp.weight = remaining * share; } } } CalculateWeight(); } public void DrawLayout() { Rect rect = StartLayout(isHorz); { Draw(rect); } EndLayout(isHorz); } private void RefreshSpliterPos(int index, float px) { Info sp1 = splits[index]; int rightIndex = -1; for (int j = index + 1; j < splits.Count; j++) { if (splits[j].visible) { rightIndex = j; break; } } if (rightIndex < 0) return; Info sp2 = splits[rightIndex]; Rect r1 = sp1.rect; Rect r2 = sp2.rect; float w1 = sp1.weight; float w2 = sp2.weight; float tt = w1 + w2; float dd = isHorz ? r2.xMax - r1.xMin - SPLIT_SIZE : r2.yMax - r1.yMin - SPLIT_SIZE; float m = isHorz ? Event.current.mousePosition.x - r1.x : Event.current.mousePosition.y - r1.y; // Enforce minimum pixel sizes for panels that prefer keeping pixel size float leftMin = 0f; float rightMin = 0f; if (sp1.sizePolicy == Info.SizePolicy.KeepPixel) leftMin = Mathf.Max(0f, sp1.minPixel); if (sp2.sizePolicy == Info.SizePolicy.KeepPixel) rightMin = Mathf.Max(0f, sp2.minPixel); float lower = Mathf.Min(dd - rightMin, leftMin); float upper = Mathf.Max(leftMin, dd - rightMin); m = Mathf.Clamp(m, lower, upper); float pct = Mathf.Min(0.9f, Mathf.Max(0.1f, m / dd)); sp1.weight = tt * pct; sp2.weight = tt * (1 - pct); dirty = true; if (window != null) window.WillRepaint = true; } private void DrawSpliter(int index, float px) { Rect dRect = _rect; if (isHorz) { dRect.x = px; dRect.width = SPLIT_SIZE; } else { dRect.y = px; dRect.height = SPLIT_SIZE; } if (Event.current.type == EventType.Repaint || Event.current.type == EventType.MouseMove) GUI2.Rect(dRect, Color.black, 0.4f); var dRect2 = GUI2.Padding(dRect, -2f, -2f); EditorGUIUtility.AddCursorRect(dRect2, isHorz ? MouseCursor.ResizeHorizontal : MouseCursor.ResizeVertical); if ((Event.current.type == EventType.MouseDown) && dRect2.Contains(Event.current.mousePosition)) { resizeIndex = index; RefreshSpliterPos(index, px); hasResize = true; } if (resizeIndex == index) RefreshSpliterPos(index, px); if (Event.current.type == EventType.MouseUp) { resizeIndex = -1; hasResize = false; } } private Rect StartLayout(bool horz) { return horz ? EditorGUILayout.BeginHorizontal(expandWH) : EditorGUILayout.BeginVertical(expandWH); } private void EndLayout(bool horz) { if (horz) { EditorGUILayout.EndHorizontal(); } else { EditorGUILayout.EndVertical(); } } [Serializable] internal class Info { public GUIContent title; public Rect rect; public float normWeight; public int stIndex; public bool visible = true; public float weight = 1f; public Action draw; public enum SizePolicy { Flexible, KeepPixel } public SizePolicy sizePolicy = SizePolicy.Flexible; public float preferredPixel = 200f; public float minPixel = 50f; // Dynamic title support public Func GetDynamicTitle; // Drawer dirty state support public Func GetDrawerDirtyState; // Refresh action support public Action OnRefresh; public void DoDraw() { Rect drawRect = rect; // Use dynamic title if available, otherwise use static title GUIContent baseTitle = GetDynamicTitle?.Invoke() ?? title; if (baseTitle != null) { var titleRect = new Rect(rect.x, rect.y, rect.width, 20f); GUI2.Rect(titleRect, Color.black, 0.2f); titleRect.xMin += 4f; // Check dirty state and modify title accordingly Color originalColor = GUI.contentColor; bool isDirty = GetDrawerDirtyState?.Invoke() ?? false; // Create title with asterisk if dirty string titleText = baseTitle.text; if (isDirty && !titleText.EndsWith("*")) { titleText += "*"; // Use theme-appropriate dirty indicator color instead of hardcoded yellow GUI.contentColor = EditorGUIUtility.isProSkin ? AssetFinderTheme.Dark.DirtyIndicator : AssetFinderTheme.Light.DirtyIndicator; } // Calculate available space for refresh button only if OnRefresh is available // Increased button width from 50f to 55f, adjusted status area accordingly float statusAreaWidth = OnRefresh != null ? (isDirty ? 205f : 55f) : 0f; // Draw main title var mainTitleRect = new Rect(titleRect.x, titleRect.y, titleRect.width - statusAreaWidth, titleRect.height); GUI.Label(mainTitleRect, new GUIContent(titleText, baseTitle.image, baseTitle.tooltip), EditorStyles.label); // Draw status message and refresh button only if OnRefresh is available if (OnRefresh != null) { if (isDirty) { // Status message - shorter text to fit var statusRect = new Rect(mainTitleRect.xMax + 5f, titleRect.y + 2f, 145f, titleRect.height); GUI.contentColor = new Color(0.7f, 0.7f, 0.7f, 0.8f); // Very dim color GUI.Label(statusRect, "* possibly incomplete result", EditorStyles.miniLabel); } GUI.contentColor = originalColor; // Increased refresh button width from 50f to 55f var refreshRect = new Rect(titleRect.xMax - 55f, titleRect.y + 1f, 53f, 14f); if (GUI.Button(refreshRect, "Refresh", EditorStyles.miniButtonRight)) { OnRefresh.Invoke(); } } GUI.contentColor = originalColor; drawRect.yMin += 20f; } draw(drawRect); } } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/UI/AssetFinderSplitView.cs.meta ================================================ fileFormatVersion: 2 guid: dfa4ea84b5e859444a6fa014c2ef93a1 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/UI/AssetFinderTabView.cs ================================================ using System; using System.Collections.Generic; using UnityEditor; using UnityEngine; namespace VirtueSky.AssetFinder.Editor { internal class DrawCallback { public Action AfterDraw; public Action BeforeDraw; } internal class AssetFinderTabView { private readonly List labelWidths = new List(); public DrawCallback callback; public bool canDeselectAll; // Can there be no active tabs public int current; public bool flexibleWidth = true; public GUIContent[] labels; private float labelTotalWidth; public float offsetFirst; public float offsetLast; public Action onTabChange; public float padding = 4f; // Cached Rects for layout to avoid GC private Rect toolbarRect; public IWindow window; public AssetFinderTabView(IWindow w, bool canDeselectAll) { window = w; this.canDeselectAll = canDeselectAll; } public bool DrawLayout() { var result = false; // Define the toolbar rect GUIStyle style = EditorStyles.toolbarButton; // Set up label rects if not already done if (labelTotalWidth == 0 || labelWidths.Count != labels.Length) { labelTotalWidth = 0; labelWidths.Clear(); for (var i = 0; i < labels.Length; i++) { float w = style.CalcSize(labels[i]).x; labelWidths.Add(w); labelTotalWidth += w; } } toolbarRect = GUILayoutUtility.GetRect(0, Screen.width, 20f, 20f); GUI.Box(toolbarRect, GUIContent.none, EditorStyles.toolbar); if (!flexibleWidth) toolbarRect.width = labelTotalWidth + labels.Length * padding; // Call before draw action if available callback?.BeforeDraw?.Invoke(toolbarRect); // Draw each tab Rect tabRect = toolbarRect; tabRect.xMin += offsetFirst; tabRect.xMax -= offsetLast; // float ratio = flexibleWidth ? ((toolbarRect.width - offsetFirst - offsetLast) / labelTotalWidth) : 1; float flexSpace = Mathf.Max(0, tabRect.width - labelTotalWidth) / labels.Length; float pad = flexibleWidth ? flexSpace : padding; for (var i = 0; i < labels.Length; i++) { bool isActive = i == current; GUIContent lb = labels[i]; // Define the toggle rect float w = labelWidths[i] + pad; tabRect.width = w; // Draw the toggle (or button) for the tab bool clicked = lb.image != null ? GUI2.ToolbarToggle(ref isActive, lb.image, Vector2.zero, lb.tooltip, tabRect) : GUI2.Toggle(ref isActive, lb, EditorStyles.toolbarButton, tabRect); tabRect.x += w; if (!clicked) { continue; } // Update the current tab and handle tab change logic current = !isActive && canDeselectAll ? -1 : i; result = true; onTabChange?.Invoke(); if (window != null) { // Tab changes only trigger repaint, NOT selection change window.WillRepaint = true; } } // Call after draw action if available callback?.AfterDraw?.Invoke(toolbarRect); return result; } public static AssetFinderTabView FromEnum(Type enumType, IWindow w, bool canDeselectAll = false) { Array values = Enum.GetValues(enumType); var labels = new List(); foreach (object item in values) { labels.Add(AssetFinderGUIContent.FromString(item.ToString())); } return new AssetFinderTabView(w, canDeselectAll) { current = 0, labels = labels.ToArray() }; } public static GUIContent GetGUIContent(object tex) { if (tex is GUIContent content) return content; if (tex is Texture texture) return AssetFinderGUIContent.FromTexture(texture); if (tex is string s) return AssetFinderGUIContent.FromString(s); return GUIContent.none; } public static AssetFinderTabView Create(IWindow w, bool canDeselectAll = false, params object[] titles) { var labels = new List(); foreach (object item in titles) { labels.Add(GetGUIContent(item)); } return new AssetFinderTabView(w, canDeselectAll) { current = 0, labels = labels.ToArray() }; } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/UI/AssetFinderTabView.cs.meta ================================================ fileFormatVersion: 2 guid: e7d63b905dd16f547bdbbd0a004b7871 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/UI/AssetFinderToggleList.cs ================================================ using System; using System.Collections.Generic; using UnityEngine; namespace VirtueSky.AssetFinder.Editor { internal class AssetFinderToggleList { public int current; public List listInfo = new List(); public AssetFinderToggleList AddInfo(GUIContent content, bool status, Action onChange, float w = 20f) { listInfo.Add(new Info { contentOn = content, contentOff = content, status = status, onChange = onChange, w = w }); return this; } public AssetFinderToggleList AddInfo(GUIContent contentOn, GUIContent contentOff, Action onChange, float w = 20) { listInfo.Add(new Info { contentOn = contentOn, contentOff = contentOff, status = false, onChange = onChange, w = w }); return this; } public AssetFinderToggleList AddInfo(GUIContent content, Action onChange, float w = 20) { listInfo.Add(new Info { contentOn = content, contentOff = content, status = false, onChange = onChange, w = w }); return this; } public AssetFinderToggleList AddInfo(GUIContent content, float w = 20) { listInfo.Add(new Info { contentOn = content, contentOff = content, w = w }); return this; } public void Draw(ref Rect rect) { if (Event.current.type == EventType.Layout) return; for (var i = 0; i < listInfo.Count; i++) { Info info = listInfo[i]; rect.width = info.w; if (GUI2.ToolbarToggle(rect, ref info.status, info.status ? info.contentOn : info.contentOff)) { info.onChange?.Invoke(info.status); } rect.x += info.w; } } public void Draw(ref Rect rect, int index, ref bool b1) { if (Event.current.type == EventType.Layout) return; Info info = listInfo[index]; rect.width = info.w; if (GUI2.ToolbarToggle(rect, ref b1, b1 ? info.contentOn : info.contentOff)) { if (info.onChange != null) info.onChange(info.status); } ; // GUI.DrawTexture(rect, Texture2D.whiteTexture); rect.x += info.w; } internal class Info { public GUIContent contentOff; public GUIContent contentOn; public Action onChange; public bool status; public float w; } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/UI/AssetFinderToggleList.cs.meta ================================================ fileFormatVersion: 2 guid: e9dfce69fdd06414bae56925dae0aa1e MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/UI/Theme/AssetFinderTheme.Dark.cs ================================================ using UnityEngine; namespace VirtueSky.AssetFinder.Editor { partial class AssetFinderTheme { private static AssetFinderTheme CreateDarkTheme() { return new AssetFinderTheme { SelectionHighlight = new Color(0.2745f, 0.4902f, 0.7451f, 1f), // Unity's dark theme selection SelectionHighlightInactive = new Color(0.3f, 0.3f, 0.3f, 1f), ErrorColor = new Color(0.8235f, 0.1333f, 0.1333f, 1f), WarningColor = new Color(0.9569f, 0.7373f, 0.0078f, 1f), InfoColor = new Color(0.2980f, 0.4941f, 1.0f, 1f), SuccessColor = new Color(0.0f, 0.8f, 0.0f, 1f), SceneHighlight = new Color32(72, 150, 191, 255), SeparatorLine = Color.black, DirtyIndicator = new Color(1f, 0.9f, 0.4f, 1f) }; } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/UI/Theme/AssetFinderTheme.Dark.cs.meta ================================================ fileFormatVersion: 2 guid: e46df44b8004036419808d338f909aa3 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/UI/Theme/AssetFinderTheme.Light.cs ================================================ using UnityEngine; namespace VirtueSky.AssetFinder.Editor { partial class AssetFinderTheme { private static AssetFinderTheme CreateLightTheme() { return new AssetFinderTheme { SelectionHighlight = new Color(0.2275f, 0.4471f, 0.6902f, 1f), // Unity's light theme selection SelectionHighlightInactive = new Color(0.6824f, 0.6824f, 0.6824f, 1f), ErrorColor = new Color(0.3529f, 0.0f, 0.0f, 1f), WarningColor = new Color(0.2f, 0.2f, 0.0314f, 1f), InfoColor = new Color(0.2980f, 0.4941f, 1.0f, 1f), SuccessColor = new Color(0.0f, 0.8f, 0.0f, 1f), SceneHighlight = Color.blue, SeparatorLine = new Color(0.6f, 0.6f, 0.6f, 1f), DirtyIndicator = new Color(0.8f, 0.7f, 0.2f, 1f) }; } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/UI/Theme/AssetFinderTheme.Light.cs.meta ================================================ fileFormatVersion: 2 guid: d4e241366471be14f92379c7cfac41a8 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/UI/Theme/AssetFinderTheme.cs ================================================ using UnityEngine; using UnityEditor; namespace VirtueSky.AssetFinder.Editor { internal partial class AssetFinderTheme { public static AssetFinderTheme Current => Dark; public static AssetFinderTheme Dark { get; } = CreateDarkTheme(); public static AssetFinderTheme Light { get; } = CreateLightTheme(); private AssetFinderTheme() { InitializeLayoutOptions(); } private void InitializeLayoutOptions() { ToolbarHeightOption = GUILayout.Height(ToolbarHeight); CompactButtonHeight = GUILayout.Height(16f); StandardButtonHeight = GUILayout.Height(18f); ActionButtonHeight = GUILayout.Height(30f); CancelButtonHeight = GUILayout.Height(25f); WarningCloseButtonHeight = GUILayout.Height(38f); CloseButtonWidth = GUILayout.Width(20f); ToolbarButtonWidth = GUILayout.Width(24f); IconButtonWidth = GUILayout.Width(IconButtonSize); RefreshButtonWidth = GUILayout.Width(RefreshButtonSize); ApplyButtonWidth = GUILayout.Width(100f); TabPanelWidth = GUILayout.Width(160f); RecursiveSearchLabelWidth = GUILayout.Width(100f); ToggleWidth = GUILayout.Width(20f); SelectionPanelWidth = GUILayout.Width(150f); ViewModeSelectorWidth = GUILayout.Width(200f); SettingsPanelHeight = GUILayout.Height(100f); DropdownWidth = GUILayout.Width(320f); LockButtonWidth = GUILayout.Width(150f); } // ============ METRICS ============ public readonly float ToolbarHeight = 30f; public readonly float TreeItemHeight = 18f; public readonly float TreeItemSpacing = 1f; public readonly float TreeContentPadding = 2f; public readonly float TreeIndentSize = 18f; public readonly float TreeToggleSize = 16f; public readonly float AssetIconSize = 16f; public readonly float IconButtonSize = 24f; public readonly float RefreshButtonSize = 18f; public readonly float ScrollBarWidth = 18f; public readonly float CompactSpacing = 4f; public readonly float FooterButtonsOffset = 100f; public readonly float TreeItemOffset = 18f; public readonly float ViewModeSelectorWidthValue = 200f; // ============ LAYOUT OPTIONS ============ public GUILayoutOption ToolbarHeightOption; public GUILayoutOption CompactButtonHeight; public GUILayoutOption StandardButtonHeight; public GUILayoutOption ActionButtonHeight; public GUILayoutOption CancelButtonHeight; public GUILayoutOption WarningCloseButtonHeight; public GUILayoutOption CloseButtonWidth; public GUILayoutOption ToolbarButtonWidth; public GUILayoutOption IconButtonWidth; public GUILayoutOption RefreshButtonWidth; public GUILayoutOption ApplyButtonWidth; public GUILayoutOption TabPanelWidth; public GUILayoutOption RecursiveSearchLabelWidth; public GUILayoutOption ToggleWidth; public GUILayoutOption SelectionPanelWidth; public GUILayoutOption ViewModeSelectorWidth; public GUILayoutOption SettingsPanelHeight; public GUILayoutOption DropdownWidth; public GUILayoutOption LockButtonWidth; // ============ COLORS ============ public Color SelectionHighlight; public Color SelectionHighlightInactive; public Color ErrorColor; public Color WarningColor; public Color InfoColor; public Color SuccessColor; public Color SceneHighlight; public Color SeparatorLine; public Color DirtyIndicator; public Rect GetProgressBarRect() { return GUILayoutUtility.GetRect(1f, Screen.width, 18f, 18f); } public Rect GetRefreshButtonRect(Rect parentRect) { return new Rect(parentRect.xMax - AssetIconSize, parentRect.yMin - 14f, RefreshButtonSize, RefreshButtonSize); } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/UI/Theme/AssetFinderTheme.cs.meta ================================================ fileFormatVersion: 2 guid: 707044acb1e550544b801b9f78ac858a MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/UI/Theme.meta ================================================ fileFormatVersion: 2 guid: 3c2cd070a17045d98ec4a456b160665e timeCreated: 1753869076 ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/UI.meta ================================================ fileFormatVersion: 2 guid: ecd25f71eac2146a58139581a59c8ad1 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Window/AssetFinderWindowAll.CacheManager.cs ================================================ using System; using System.Collections.Generic; using UnityEditor; using UnityEngine; using UnityObject = UnityEngine.Object; namespace VirtueSky.AssetFinder.Editor { internal partial class AssetFinderWindowAll { protected void DrawScanProject() { bool writeImportLog = settings.writeImportLog; settings.writeImportLog = EditorGUILayout.Toggle("Write Import Log", settings.writeImportLog); if (writeImportLog != settings.writeImportLog) { EditorUtility.SetDirty(this); } if (GUILayout.Button("Scan project")) { AssetFinderAsset.shouldWriteImportLog = writeImportLog; AssetFinderCache.DeleteCache(); AssetFinderCache.CreateCache(); } } protected bool CheckDrawImport() { AssetFinderUnity.RefreshEditorStatus(); if (AssetFinderUnity.isEditorCompiling) { EditorGUILayout.HelpBox("Compiling scripts, please wait!", MessageType.Warning); Repaint(); return false; } if (AssetFinderUnity.isEditorUpdating) { EditorGUILayout.HelpBox("Importing assets, please wait!", MessageType.Warning); Repaint(); return false; } InitIfNeeded(); if (EditorSettings.serializationMode != SerializationMode.ForceText) { EditorGUILayout.HelpBox("FR2 requires serialization mode set to FORCE TEXT!", MessageType.Warning); if (GUILayout.Button("FORCE TEXT")) EditorSettings.serializationMode = SerializationMode.ForceText; return false; } if (AssetFinderCache.hasCache && !AssetFinderCache.CheckSameVersion()) { 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!", MessageType.Warning); DrawScanProject(); return false; } if (AssetFinderCache.isReady) return DrawEnable(); if (!AssetFinderCache.hasCache) { EditorGUILayout.HelpBox( "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!", MessageType.Warning); DrawScanProject(); return false; } if (!DrawEnable()) return false; AssetFinderCache api = AssetFinderCache.Api; if (api.workCount > 0) { string text = "Refreshing ... " + (int)(api.progress * api.workCount) + " / " + api.workCount; // Show current asset being processed if (!string.IsNullOrEmpty(api.currentAssetName)) { EditorGUILayout.LabelField(api.currentAssetName, EditorStyles.miniLabel); } Rect rect = GUILayoutUtility.GetRect(1f, Screen.width, 18f, 18f); EditorGUI.ProgressBar(rect, api.progress, text); Repaint(); } else { api.workCount = 0; api.ready = true; } return false; } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Window/AssetFinderWindowAll.CacheManager.cs.meta ================================================ fileFormatVersion: 2 guid: 1c11665c77d8bb74b89a3b61ef10a1be MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Window/AssetFinderWindowAll.Drawing.cs ================================================ using System; using System.Collections.Generic; using UnityEditor; using UnityEngine; using UnityObject = UnityEngine.Object; namespace VirtueSky.AssetFinder.Editor { internal partial class AssetFinderWindowAll { private void DrawScenePanel(Rect rect) { AssetFinderRefDrawer drawer = isFocusingUses ? IsSelectingAssets ? null : SceneUsesDrawer : IsSelectingAssets ? RefInScene : RefSceneInScene; if (drawer == null) return; if (!AssetFinderSceneCache.isReady && AssetFinderSceneCache.Api.Status == SceneCacheStatus.Scanning) { DrawSceneCacheProgress(rect); rect.yMin += 18f; } if (AssetFinderSceneCache.hasCache) drawer.Draw(rect); } private void DrawSceneCacheProgress(Rect rect) { Rect rr = rect; rr.height = 16f; if (AssetFinderSceneCache.Api.Status == SceneCacheStatus.Scanning) { int cur = AssetFinderSceneCache.Api.current, total = AssetFinderSceneCache.Api.total; var progress = Mathf.Clamp01(cur * 1f / total); var progressText = AssetFinderSceneCache.Api.Status == SceneCacheStatus.Scanning ? $"Scanning objects: {cur} / {total}" : $"{cur} / {total}"; EditorGUI.ProgressBar(rr, progress, progressText); if (cur >= total) { AssetFinderLOG.LogWarning($"Stuck at scanning? {cur}/{total}"); } WillRepaint = true; return; } string statusText; switch (AssetFinderSceneCache.Api.Status) { case SceneCacheStatus.None: statusText = "Scene cache is not ready!"; break; case SceneCacheStatus.Changed: statusText = "Scene changed - results might be incompleted"; break; case SceneCacheStatus.Scanning: statusText = "Preparing to scan scene objects..."; break; case SceneCacheStatus.Ready: statusText = "Scene cache ready"; break; default: statusText = "Unknown status"; break; } EditorGUI.ProgressBar(rr, 0f, statusText); } private void DrawAssetPanel(Rect rect) { AssetFinderRefDrawer drawer = GetAssetDrawer(); if (drawer == null) return; drawer.Draw(rect); if (!drawer.showDetail) return; settings.details = true; drawer.showDetail = false; sp1.splits[2].visible = settings.details; sp1.CalculateWeight(); Repaint(); } private void DrawGitWarningPanel() { if (!AssetFinderSettingExt.isGitProject || AssetFinderSettingExt.gitIgnoreAdded || AssetFinderSettingExt.hideGitIgnoreWarning) return; EditorGUILayout.BeginHorizontal(); // Left side: Warning message EditorGUILayout.BeginVertical(GUILayout.ExpandWidth(true)); EditorGUILayout.HelpBox("You should add **/AssetFinderCache.asset* to your .gitignore file to avoid committing cache files.", MessageType.Warning); EditorGUILayout.EndVertical(); // Right side: Buttons stacked vertically EditorGUILayout.BeginVertical(AssetFinderTheme.Current.ApplyButtonWidth); if (GUILayout.Button("Apply", AssetFinderTheme.Current.CompactButtonHeight)) { AssetFinderGitUtil.AddFR2CacheToGitIgnore(); AssetFinderSettingExt.gitIgnoreAdded = true; } if (GUILayout.Button("Ignore", AssetFinderTheme.Current.CompactButtonHeight)) { AssetFinderSettingExt.hideGitIgnoreWarning = true; } EditorGUILayout.EndVertical(); EditorGUILayout.EndHorizontal(); } private void DrawToolsWarningPanel() { if (AssetFinderSettingExt.hideToolsWarning) return; EditorGUILayout.BeginHorizontal(); EditorGUILayout.HelpBox(AssetFinderGUIContent.From("Tools are POWERFUL & DANGEROUS! Only use if you know what you are doing!!!", AssetFinderIcon.Warning.image)); if (GUILayout.Button(" x", EditorStyles.label, AssetFinderTheme.Current.CloseButtonWidth, AssetFinderTheme.Current.WarningCloseButtonHeight)) { AssetFinderSettingExt.hideToolsWarning = true; } EditorGUILayout.EndHorizontal(); } internal bool DrawButton(Rect rect, ref bool show, GUIContent icon) { var changed = false; Color oColor = GUI.color; Color originalContentColor = GUI.contentColor; // For light theme, make icons more visible by adjusting content color if (!EditorGUIUtility.isProSkin) { GUI.contentColor = new Color(0.3f, 0.3f, 0.3f, 1f); // Darker color for better visibility in light theme } if (show) GUI.color = new Color(0.7f, 1f, 0.7f, 1f); { if (GUI.Button(rect, icon, EditorStyles.toolbarButton)) { show = !show; EditorUtility.SetDirty(this); WillRepaint = true; changed = true; } } GUI.color = oColor; GUI.contentColor = originalContentColor; return changed; } internal void DrawAssetViewSettings() { bool isDisable = !sp2.splits[1].visible; EditorGUI.BeginDisabledGroup(isDisable); { GUI2.ToolbarToggle(ref AssetFinderSetting.s.displayAssetBundleName, AssetFinderIcon.AssetBundle.image, Vector2.zero, "Show / Hide Assetbundle Names"); #if UNITY_2017_1_OR_NEWER GUI2.ToolbarToggle(ref AssetFinderSetting.s.displayAtlasName, AssetFinderIcon.Atlas.image, Vector2.zero, "Show / Hide Atlas packing tags"); #endif GUI2.ToolbarToggle(ref AssetFinderSetting.s.showUsedByClassed, AssetFinderIcon.Material.image, Vector2.zero, "Show / Hide usage icons"); if (GUILayout.Button("CSV", EditorStyles.toolbarButton)) OnCSVClickExtension(); } EditorGUI.EndDisabledGroup(); } private AssetFinderEnumDrawer groupModeED; private AssetFinderEnumDrawer toolModeED; private AssetFinderEnumDrawer sortModeED; internal void DrawViewModes(Rect rect) { var (rect1, rect2) = rect.HzSplit(0f, 0.5f); if (toolModeED == null) { toolModeED = new AssetFinderEnumDrawer { AssetFinderenum = new AssetFinderEnumDrawer.EnumInfo( AssetFinderRefDrawer.Mode.Type, AssetFinderRefDrawer.Mode.Folder, AssetFinderRefDrawer.Mode.Extension ) }; } if (groupModeED == null) groupModeED = new AssetFinderEnumDrawer { tooltip = "Group By" }; if (sortModeED == null) sortModeED = new AssetFinderEnumDrawer { tooltip = "Sort By" }; if (settings.toolMode) { AssetFinderRefDrawer.Mode tMode = settings.toolGroupMode; if (toolModeED.Draw(rect1, ref tMode)) { settings.toolGroupMode = tMode; MarkDirty(); RefreshSort(); } } else { AssetFinderRefDrawer.Mode gMode = settings.groupMode; if (groupModeED.Draw(rect1, ref gMode)) { settings.groupMode = gMode; MarkDirty(); RefreshSort(); } } AssetFinderRefDrawer.Sort sMode = settings.sortMode; if (sortModeED.Draw(rect2, ref sMode)) { settings.sortMode = sMode; RefreshSort(); } } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Window/AssetFinderWindowAll.Drawing.cs.meta ================================================ fileFormatVersion: 2 guid: ed565692c3c6a724fb0f4e66603f1662 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Window/AssetFinderWindowAll.GuidManager.cs ================================================ using System; using System.Collections.Generic; using UnityEditor; using UnityEngine; using UnityObject = UnityEngine.Object; namespace VirtueSky.AssetFinder.Editor { internal partial class AssetFinderWindowAll { private Dictionary guidObjs; private Vector2 scrollPos; private string tempGUID; private string tempFileID; private UnityObject tempObject; private void DrawGUIDs() { GUILayout.Label("GUID to Object", EditorStyles.boldLabel); GUILayout.BeginHorizontal(); { string guid = EditorGUILayout.TextField(tempGUID ?? string.Empty); string fileId = EditorGUILayout.TextField(tempFileID ?? string.Empty); EditorGUILayout.ObjectField(tempObject, typeof(UnityObject), false, GUI2.GLW_160); if (GUILayout.Button("Paste", EditorStyles.miniButton, GUI2.GLW_70)) { string[] split = EditorGUIUtility.systemCopyBuffer.Split('/'); guid = split[0]; fileId = split.Length == 2 ? split[1] : string.Empty; } if ((guid != tempGUID || fileId != tempFileID) && !string.IsNullOrEmpty(guid)) { tempGUID = guid; tempFileID = fileId; string fullId = string.IsNullOrEmpty(fileId) ? tempGUID : tempGUID + "/" + tempFileID; tempObject = AssetFinderUnity.LoadAssetAtPath ( AssetDatabase.GUIDToAssetPath(fullId) ); } if (GUILayout.Button("Set FileID")) { var newDict = new Dictionary(); foreach (KeyValuePair kvp in guidObjs) { string key = kvp.Key.Split('/')[0]; if (!string.IsNullOrEmpty(fileId)) key = key + "/" + fileId; var value = AssetFinderUnity.LoadAssetAtPath ( AssetDatabase.GUIDToAssetPath(key) ); newDict.Add(key, value); } guidObjs = newDict; } } GUILayout.EndHorizontal(); GUILayout.Space(10f); if (guidObjs == null) { GUILayout.FlexibleSpace(); return; } scrollPos = GUILayout.BeginScrollView(scrollPos); { foreach (KeyValuePair item in guidObjs) { GUILayout.BeginHorizontal(); { UnityObject obj = item.Value; EditorGUILayout.ObjectField(obj, typeof(UnityObject), false, GUI2.GLW_150); string idi = item.Key; GUILayout.TextField(idi, GUI2.GLW_320); if (GUILayout.Button(AssetFinderGUIContent.FromString("Copy"), EditorStyles.miniButton, GUI2.GLW_50)) { tempObject = obj; string[] arr = item.Key.Split('/'); tempGUID = arr[0]; tempFileID = arr[1]; } } GUILayout.EndHorizontal(); } } GUILayout.EndScrollView(); GUILayout.BeginHorizontal(); if (GUILayout.Button("Merge Selection To")) { string fullId = string.IsNullOrEmpty(tempFileID) ? tempGUID : tempGUID + "/" + tempFileID; AssetFinderExport.MergeDuplicate(fullId); } EditorGUILayout.ObjectField(tempObject, typeof(UnityObject), false, GUI2.GLW_120); GUILayout.EndHorizontal(); GUILayout.FlexibleSpace(); } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Window/AssetFinderWindowAll.GuidManager.cs.meta ================================================ fileFormatVersion: 2 guid: a0b54e82f6de36e489536582ac285f6c MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Window/AssetFinderWindowAll.Initialization.cs ================================================ using System; using System.Collections.Generic; using UnityEditor; using UnityEngine; using UnityObject = UnityEngine.Object; namespace VirtueSky.AssetFinder.Editor { internal partial class AssetFinderWindowAll { private void InitializeComponents() { // Initialize UI components first to ensure selection exists before selection manager events InitializeUIComponents(); InitializeNavigationHistory(); InitializeDrawers(); InitializeTools(); InitializeDrawerProperties(); InitTabs(); InitPanes(); // Initialize selection manager AFTER everything else is ready InitializeSelectionManager(); if (AssetFinderCache.isReady) { RefreshActiveTab(); RefreshFR2View(); } else { // Debug.LogWarning("FR2 is not Ready just yet!"); AssetFinderCache.onReady -= RefreshActiveTab; AssetFinderCache.onReady += RefreshActiveTab; AssetFinderCache.onReady -= RefreshFR2View; AssetFinderCache.onReady += RefreshFR2View; } Repaint(); } void RefreshActiveTab() { AssetFinderCache.onReady -= RefreshActiveTab; AssetFinderCache.onReady -= RefreshFR2View; // If tabs are not initialized yet, we'll defer this call // OnGUI2 will handle calling tab changes when tabs are initialized if (tabs == null || toolTabs == null) { return; } if (settings.toolMode) { toolTabs.onTabChange?.Invoke(); } else { tabs.onTabChange?.Invoke(); } // If selection was out of sync due to cache not being ready, sync now if (isSelectionOutOfSync && selection != null && !selection.isLock) { selection.SyncFromGlobalSelection(); RefreshFR2View(); isSelectionOutOfSync = false; } } private void InitializeNavigationHistory() { if (navigationHistory == null) navigationHistory = new AssetFinderNavigationHistory(); navigationHistory.SetWindow(this); } private void InitializeSelectionManager() { AssetFinderSelectionManager.SelectionChanged -= OnSelectionManagerChanged; AssetFinderSelectionManager.SelectionChanged += OnSelectionManagerChanged; } private void InitializeDrawers() { UsesDrawer = new AssetFinderRefDrawer(new AssetFinderRefDrawer.AssetDrawingConfig { window = this, getSortMode = () => settings.sortMode, getGroupMode = () => settings.groupMode, showFullPath = settings.showFullPath, showFileSize = settings.showFileSize, showExtension = settings.showFileExtension, showUsageType = settings.showUsageType, showAssetBundleName = AssetFinderSetting.s.displayAssetBundleName, showAtlasName = AssetFinderSetting.s.displayAtlasName, showToggle = true, shouldShowExtension = () => settings.showFileExtension, shouldShowDetailButton = () => true, onCacheInvalidated = () => { } }) { messageEmpty = "[Selected Assets] are not [USING] (depends on / contains reference to) any other assets!", GetContextualEmptyMessage = () => cachedUsesMessage }; UsedByDrawer = new AssetFinderRefDrawer(new AssetFinderRefDrawer.AssetDrawingConfig { window = this, getSortMode = () => settings.sortMode, getGroupMode = () => settings.groupMode, showFullPath = settings.showFullPath, showFileSize = settings.showFileSize, showExtension = settings.showFileExtension, showUsageType = settings.showUsageType, showAssetBundleName = AssetFinderSetting.s.displayAssetBundleName, showAtlasName = AssetFinderSetting.s.displayAtlasName, showToggle = true, shouldShowExtension = () => settings.showFileExtension, shouldShowDetailButton = () => !isFocusingUsedBy, onCacheInvalidated = () => { } }) { messageEmpty = "[Selected Assets] are not [USED BY] any other assets!", GetContextualEmptyMessage = () => cachedUsedByMessage }; AddressableDrawer = new AssetFinderAddressableDrawer(this, () => settings.sortMode, () => settings.groupMode); Duplicated = new AssetFinderDuplicateTree2(this, () => settings.sortMode, () => settings.toolGroupMode); RefInScene = new AssetFinderRefDrawer(new AssetFinderRefDrawer.SceneDrawingConfig { window = this, getSortMode = () => settings.sortMode, getGroupMode = () => settings.groupMode, showFullPath = settings.showFullPath, showDetails = true, showToggle = true, shouldShowExtension = () => settings.showFileExtension, shouldShowDetailButton = () => true, onCacheInvalidated = () => { } }) { messageEmpty = "[Selected Assets] are not [USED BY] any GameObjects in current scene!", GetContextualEmptyMessage = () => cachedRefInSceneMessage }; RefSceneInScene = new AssetFinderRefDrawer(new AssetFinderRefDrawer.SceneDrawingConfig { window = this, getSortMode = () => settings.sortMode, getGroupMode = () => settings.groupMode, showFullPath = settings.showFullPath, showDetails = true, showToggle = true, shouldShowExtension = () => settings.showFileExtension, shouldShowDetailButton = () => true, onCacheInvalidated = () => { } }) { messageEmpty = "[Selected GameObjects] are not [USED BY] any GameObjects in current scene!", GetContextualEmptyMessage = () => cachedSceneInSceneMessage }; SceneUsesDrawer = new AssetFinderRefDrawer(new AssetFinderRefDrawer.SceneDrawingConfig { window = this, getSortMode = () => settings.sortMode, getGroupMode = () => settings.groupMode, showFullPath = settings.showFullPath, showDetails = true, showToggle = true, shouldShowExtension = () => settings.showFileExtension, shouldShowDetailButton = () => true, onCacheInvalidated = () => { } }) { messageEmpty = "[Selected GameObjects] are not [USING] any GameObjects in current scene!", GetContextualEmptyMessage = () => cachedSceneUsesMessage }; SceneToAssetDrawer = new AssetFinderRefDrawer(new AssetFinderRefDrawer.AssetDrawingConfig { window = this, getSortMode = () => settings.sortMode, getGroupMode = () => settings.groupMode, showFullPath = settings.showFullPath, showFileSize = settings.showFileSize, showExtension = settings.showFileExtension, showUsageType = settings.showUsageType, showAssetBundleName = AssetFinderSetting.s.displayAssetBundleName, showAtlasName = AssetFinderSetting.s.displayAtlasName, showToggle = true, shouldShowExtension = () => settings.showFileExtension, shouldShowDetailButton = () => true, onCacheInvalidated = () => { } }) { messageEmpty = "[Selected GameObjects] are not [USING] any assets!", GetContextualEmptyMessage = () => cachedSceneToAssetMessage }; RefUnUse = new AssetFinderRefDrawer(new AssetFinderRefDrawer.AssetDrawingConfig { window = this, getSortMode = () => settings.sortMode, getGroupMode = () => settings.toolGroupMode, showFullPath = settings.showFullPath, showFileSize = settings.showFileSize, showExtension = settings.showFileExtension, showUsageType = settings.showUsageType, showAssetBundleName = AssetFinderSetting.s.displayAssetBundleName, showAtlasName = AssetFinderSetting.s.displayAtlasName, showToggle = true, shouldShowExtension = () => settings.showFileExtension, shouldShowDetailButton = () => !isFocusingUnused, onCacheInvalidated = () => { } }) { messageEmpty = "Wow! No unused assets found!", // RefUnUse doesn't need contextual messages as it's not selection-dependent }; } private void InitializeTools() { UsedInBuild = new AssetFinderUsedInBuild(this, () => settings.sortMode, () => settings.toolGroupMode); MissingReference = new AssetFinderMissingReference(this, () => settings.sortMode, () => settings.toolGroupMode); AssetOrganizer = new AssetFinderAssetOrganizer(this, () => settings.sortMode, () => settings.toolGroupMode); DeleteEmptyFolder = new AssetFinderDeleteEmptyFolder(this, () => settings.sortMode, () => settings.toolGroupMode); } private void InitializeUIComponents() { selection = new AssetFinderSelection(this, () => settings.sortMode, () => settings.groupMode); selection.OnSelectionChanged -= OnLocalSelectionChanged; selection.OnSelectionChanged += OnLocalSelectionChanged; bookmark = new AssetFinderBookmark(this, () => settings.sortMode, () => settings.groupMode); // Setup bookmark cache invalidation callback - each drawer will invalidate its own cache AssetFinderBookmark.OnBookmarkChanged = () => { UsesDrawer?.InvalidateGroupCache(); UsedByDrawer?.InvalidateGroupCache(); RefUnUse?.InvalidateGroupCache(); RefInScene?.InvalidateGroupCache(); SceneToAssetDrawer?.InvalidateGroupCache(); SceneUsesDrawer?.InvalidateGroupCache(); RefSceneInScene?.InvalidateGroupCache(); }; // Initial sync with Unity selection - sync immediately if cache is ready if (AssetFinderCache.isReady && selection != null) { selection.SyncFromGlobalSelection(); isSelectionOutOfSync = false; } else { // Defer sync until cache is ready EditorApplication.delayCall += () => { if (selection == null) return; if (!AssetFinderCache.isReady) return; selection.SyncFromGlobalSelection(); isSelectionOutOfSync = false; RefreshFR2View(); }; } } private void OnLocalSelectionChanged() { // When local selection changes (user interacts with selection panel), // refresh the Uses/Used By tabs to reflect the current selection if (selection != null) { // Debug.Log($"OnLocalSelectionChanged - Count: {selection.Count}, IsSelectingAsset: {selection.isSelectingAsset}, GuidCount: {selection.guidSet.Count}"); RefreshFR2View(); } } private void InitializeDrawerProperties() { this.CacheAllDrawers(); this.RefreshShowFileExtension(); this.RefreshShowFullPath(); this.RefreshShowFileSize(); this.RefreshShowUsageType(); } private void InitPanes() { sp2 = new AssetFinderSplitView(this) { isHorz = false, splits = new List { new AssetFinderSplitView.Info { title = new GUIContent("Scene", AssetFinderIcon.Scene.image), draw = DrawScene, visible = settings.scene, GetDynamicTitle = GetScenePanelTitle, GetDrawerDirtyState = IsScenePanelDirty, OnRefresh = () => AssetFinderSceneCache.Api.ForceRefresh() }, new AssetFinderSplitView.Info { title = new GUIContent("Assets", AssetFinderIcon.Asset.image), draw = DrawAsset, visible = settings.asset, GetDynamicTitle = GetAssetPanelTitle, GetDrawerDirtyState = IsAssetPanelDirty, OnRefresh = () => AssetFinderCache.Api.IncrementalRefresh() }, new AssetFinderSplitView.Info { title = null, draw = rect => AddressableDrawer.Draw(rect), visible = false } } }; sp2.CalculateWeight(); sp1 = new AssetFinderSplitView(this) { isHorz = true, splits = new List { new AssetFinderSplitView.Info { title = null, //new GUIContent("Selection"), draw = DrawSelectionPanel, weight = 0f, visible = settings.selection, sizePolicy = AssetFinderSplitView.Info.SizePolicy.KeepPixel, preferredPixel = settings.selectionPanelPixel }, new AssetFinderSplitView.Info { title = null, draw = _ => sp2.Draw(_), weight = 1f, visible = true, sizePolicy = AssetFinderSplitView.Info.SizePolicy.Flexible }, new AssetFinderSplitView.Info { title = new GUIContent("Details", AssetFinderIcon.Hierarchy.image), draw = DrawDetailsPanel, weight = 0f, visible = settings.details, sizePolicy = AssetFinderSplitView.Info.SizePolicy.KeepPixel, preferredPixel = settings.detailsPanelPixel }, new AssetFinderSplitView.Info { title = new GUIContent("Bookmark", AssetFinderIcon.Favorite.image), draw = _ => bookmark.Draw(_), weight = 0f, visible = settings.bookmark, sizePolicy = AssetFinderSplitView.Info.SizePolicy.KeepPixel, preferredPixel = settings.bookmarkPanelPixel } } }; sp1.CalculateWeight(); } private void InitTabs() { bottomTabs = AssetFinderTabView.Create(this, true, new GUIContent(AssetFinderIcon.Setting.image, "Settings"), new GUIContent(AssetFinderIcon.Ignore.image, "Ignore"), new GUIContent(AssetFinderIcon.Filter.image, "Filter by Type") ); bottomTabs.current = -1; bottomTabs.flexibleWidth = false; bottomTabs.onTabChange = () => { // Bottom tab changes work directly on FR2 selection - no locks needed }; toolTabs = AssetFinderTabView.Create(this, false, "Duplicate", "GUID", "Unused", "In Build", "Others"); toolTabs.current = settings.toolTabIndex; toolTabs.onTabChange = () => { settings.toolTabIndex = toolTabs.current; if (toolTabs.current == 0) // Duplicate { if (Duplicated != null) { Duplicated.SetDirty(); Duplicated.RefreshSort(); } } if (toolTabs.current == 1) // GUID { // GUIDs tool doesn't use drawer system, no action needed } if (toolTabs.current == 2) // Unused { if (RefUnUse != null) { RefUnUse.ResetUnusedAsset(settings.recursiveUnusedScan); RefUnUse.SetDirty(); RefUnUse.RefreshSort(); } } if (toolTabs.current == 3) // UsedInBuild { if (UsedInBuild != null) { UsedInBuild.SetDirty(); UsedInBuild.RefreshSort(); } } if (toolTabs.current == 4) // Others { // Others tab has its own internal tab system, no action needed } // Ensure proper group mode restrictions for tools that need them if (toolTabs.IsFocusingAny(2, 3)) // Unused or UsedInBuild { if (!allowedModes.Contains(settings.toolGroupMode)) { settings.toolGroupMode = AssetFinderRefDrawer.Mode.Type; } } Repaint(); }; if (AssetFinderAddressable.asmStatus == AssetFinderAddressable.ASMStatus.AsmNotFound) { // No Addressable tabs = AssetFinderTabView.Create(this, false, // , "Tools" "Uses", "Used By" ); } else { tabs = AssetFinderTabView.Create(this, false, // , "Tools" "Uses", "Used By", "Addressables" ); } tabs.onTabChange = () => { settings.mainTabIndex = tabs.current; OnTabChange(); }; tabs.current = settings.mainTabIndex; const float IconW = 24f; const float LockButtonW = 150f; // Fixed width for lock button with text const float BookmarkW = 44f; tabs.offsetFirst = IconW * 2 + LockButtonW; // prev, next, lock(with text) tabs.offsetLast = IconW * 3 + BookmarkW; tabs.callback = new DrawCallback { BeforeDraw = rect => { if (navigationHistory == null) navigationHistory = new AssetFinderNavigationHistory(); rect.width = IconW; // Previous button bool canGoBack = navigationHistory.CanGoBack; EditorGUI.BeginDisabledGroup(!canGoBack); if (GUI.Button(rect, "<", EditorStyles.toolbarButton)) { navigationHistory.GoBack(); GUIUtility.ExitGUI(); // Prevent layout errors } EditorGUI.EndDisabledGroup(); rect.x += IconW; // Next button bool canGoForward = navigationHistory.CanGoForward; EditorGUI.BeginDisabledGroup(!canGoForward); if (GUI.Button(rect, ">", EditorStyles.toolbarButton)) { navigationHistory.GoForward(); GUIUtility.ExitGUI(); // Prevent layout errors } EditorGUI.EndDisabledGroup(); rect.x += IconW; // Lock/SmartLock button area - fixed width with text content rect.width = LockButtonW; { // Normal lock button with selection count UnityObject[] fr2CurrentSelection = GetFR2Selection(); int selectionCount = fr2CurrentSelection?.Length ?? 0; // Split the button area - left side for selection info, right side for lock icon Rect selectionRect = rect; selectionRect.width = LockButtonW - 30f; // Leave space for lock icon Rect lockIconRect = rect; lockIconRect.x = selectionRect.xMax; lockIconRect.width = 30f; // Selection info button (clicking toggles selection visibility) string selectionText = selectionCount > 0 ? $"Selection ({selectionCount})" : "Selection"; GUIContent selectionContent = new GUIContent(selectionText, "Click to toggle selection panel"); // Highlight with subtle yellow if selection is out of sync Color originalBgColor = GUI.color; if (isSelectionOutOfSync) { GUI.color = new Color(1f, 1f, 0f, 1f); // Subtle yellow tint } if (GUI.Button(selectionRect, selectionContent, EditorStyles.toolbarButton)) { settings.selection = !settings.selection; sp1.splits[0].visible = settings.selection; sp1.CalculateWeight(); WillRepaint = true; } // Restore original background color GUI.color = originalBgColor; // Lock icon button (clicking locks/unlocks selection) GUIContent lockIconContent = new GUIContent( selection.isLock ? AssetFinderIcon.Lock.image : AssetFinderIcon.Unlock.image, selection.isLock ? "Unlock Selection" : "Lock Selection" ); // Set green background when locked, similar to other toggle buttons Color originalBgColor2 = GUI.backgroundColor; if (selection.isLock) { GUI.backgroundColor = new Color(0.7f, 1f, 0.7f, 1f); // Same green as other toggle buttons } if (GUI.Button(lockIconRect, lockIconContent, EditorStyles.toolbarButton)) { selection.isLock = !selection.isLock; WillRepaint = true; } // Restore original background color GUI.backgroundColor = originalBgColor2; } }, AfterDraw = rect => { rect.xMin = rect.xMax - (IconW * 3 + BookmarkW); rect.width = IconW; // Scene toggle with content indication if (GUI2.ToolbarToggle(ref settings.scene, AssetFinderIcon.Scene.image, Vector2.zero, "Show / Hide Scene References", rect, ScenePanelHasContent())) { if ((settings.asset == false) && (settings.scene == false)) { settings.asset = true; sp2.splits[1].visible = settings.asset; } RefreshPanelVisible(); Repaint(); } rect.x += IconW; if (GUI2.ToolbarToggle(ref settings.asset, AssetFinderIcon.Asset.image, Vector2.zero, "Show / Hide Asset References", rect, AssetPanelHasContent())) { if ((settings.asset == false) && (settings.scene == false)) { settings.scene = true; sp2.splits[0].visible = settings.scene; } RefreshPanelVisible(); Repaint(); } rect.x += IconW; if (GUI2.ToolbarToggle(ref settings.details, AssetFinderIcon.Details.image, Vector2.zero, "Show / Hide Details", rect)) { sp1.splits[2].visible = settings.details; sp1.CalculateWeight(); Repaint(); } rect.x += IconW; { rect.width = BookmarkW; int bookmarkCount = AssetFinderBookmark.Count; bool hasBookmarks = bookmarkCount > 0; Color originalBg = GUI.backgroundColor; if (hasBookmarks) { GUI.backgroundColor = new Color(0.7f, 1f, 0.7f, 1f); } var bookmarkTitle = AssetFinderGUIContent.FromTexture(AssetFinderIcon.Favorite.image, "Show / Hide Bookmarks"); bookmarkTitle.text = hasBookmarks ? (bookmarkCount > 99 ? "99+" : $"{bookmarkCount}") : string.Empty; if (GUI2.ToolbarToggle(rect, ref settings.bookmark, bookmarkTitle)) { sp1.splits[3].visible = settings.bookmark; sp1.CalculateWeight(); Repaint(); } GUI.backgroundColor = originalBg; } } }; } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Window/AssetFinderWindowAll.Initialization.cs.meta ================================================ fileFormatVersion: 2 guid: 9ab650bb105e74040b3f082e18327de6 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Window/AssetFinderWindowAll.PanelSettings.cs ================================================ using System; using System.Collections.Generic; namespace VirtueSky.AssetFinder.Editor { partial class AssetFinderWindowAll { [Serializable] internal class PanelSettings { public bool selection; public bool horzLayout; public bool scene = true; public bool asset = true; public bool details; public bool bookmark; public bool toolMode; public bool showFullPath = true; public bool showFileSize; public bool showFileExtension; public bool showUsageType = true; public bool writeImportLog; public bool recursiveUnusedScan = true; public AssetFinderRefDrawer.Mode toolGroupMode = AssetFinderRefDrawer.Mode.Type; public AssetFinderRefDrawer.Mode groupMode = AssetFinderRefDrawer.Mode.Dependency; public AssetFinderRefDrawer.Sort sortMode = AssetFinderRefDrawer.Sort.Path; public int mainTabIndex = 1; // For main tabs (e.g. Uses/Used By/Addressables) - Default to "Used By" public int toolTabIndex = 0; // For toolTabs (Duplicate/GUID/Unused/In Build/Others) public int othersTabIndex = 0; // For vertical tab bar in 'Others' section // Remember pixel sizes for fixed panels public float selectionPanelPixel = 200f; public float detailsPanelPixel = 150f; public float bookmarkPanelPixel = 150f; } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Window/AssetFinderWindowAll.PanelSettings.cs.meta ================================================ fileFormatVersion: 2 guid: 7756dd91425c7614ca453e83dbf68477 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Window/AssetFinderWindowAll.SelectionManager.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using UnityEditor; using UnityEngine; using UnityObject = UnityEngine.Object; namespace VirtueSky.AssetFinder.Editor { internal partial class AssetFinderWindowAll { internal UnityObject[] _cachedSelection; internal int _cachedSelectionFrame = -1; private string[] ids; private void OnSelectionManagerChanged() { if (selection == null) return; if (selection.isLock) return; // Check and consume ping lock state - if active, skip sync but hide warnings bool hadPingLock = smartLock?.ConsumePingLockState() ?? false; if (hadPingLock) { AssetFinderLOG.Log("Skipped refresh: Ping lock was active - keeping current FR2 selection!"); // Still need to check if selection is out of sync for UI highlighting var unitySelection = AssetFinderSelectionManager.Instance.GetUnitySelection(); var fr2Selection = selection.GetUnityObjects(); isSelectionOutOfSync = !AreSelectionsEqual(unitySelection, fr2Selection); WillRepaint = true; Repaint(); return; } // IMPORTANT: Always update FR2 selection regardless of cache readiness // Selection listening must work independently of cache status var shouldRefresh = smartLock.ShouldRefreshWithSmartLogic(this, selection.GetUnityObjects()); if (shouldRefresh) { selection.SyncFromGlobalSelection(); isSelectionOutOfSync = false; // Selection is now in sync // Only refresh FR2 view if cache is ready - this prevents errors but keeps selection updated if (AssetFinderCache.isReady) { RefreshFR2View(); } else { AssetFinderLOG.Log("Cache not ready - selection updated but view refresh skipped"); } } else { isSelectionOutOfSync = true; // Selection is now out of sync } WillRepaint = true; Repaint(); } private void OnDisableSelectionManager() { AssetFinderSelectionManager.SelectionChanged -= OnSelectionManagerChanged; } public override void OnSelectionChange() { // DO NOTHING } void OnPanelSelectionChanged() { if (!AssetFinderCache.isReady) return; if (SceneUsesDrawer == null) InitIfNeeded(); if (UsesDrawer == null) InitIfNeeded(); if (selection == null) return; // Additional safety check navigationHistory.SetWindow(this); // Use unified selection manager (static access only) UnityObject[] currentSelection = AssetFinderSelectionManager.Instance.GetUnitySelection(); if (currentSelection.Length > 0) { navigationHistory.RecordSelection(currentSelection); } if (isFocusingGUIDs) { if (guidObjs == null) guidObjs = new Dictionary(); else guidObjs.Clear(); for (var i = 0; i < currentSelection.Length; i++) { UnityObject item = currentSelection[i]; #if UNITY_2018_1_OR_NEWER { var guid = ""; long fileid = -1; try { if (AssetDatabase.TryGetGUIDAndLocalFileIdentifier(item, out guid, out fileid)) { guidObjs.Add(guid + "/" + fileid, currentSelection[i]); } } catch (Exception e) { AssetFinderLOG.LogWarning($"TryGetGUIDAndLocalFileIdentifier {item}\nException: {e}"); } } #else { var path = AssetDatabase.GetAssetPath(item); if (string.IsNullOrEmpty(path)) continue; var guid = AssetDatabase.AssetPathToGUID(path); System.Reflection.PropertyInfo inspectorModeInfo = typeof(SerializedObject).GetProperty("inspectorMode", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); SerializedObject serializedObject = new SerializedObject(item); inspectorModeInfo.SetValue(serializedObject, InspectorMode.Debug, null); SerializedProperty localIdProp = serializedObject.FindProperty("m_LocalIdentfierInFile"); var localId = localIdProp.longValue; if (localId <= 0) { localId = localIdProp.intValue; } if (localId <= 0) { continue; } if (!string.IsNullOrEmpty(guid)) guidObjs.Add(guid + "/" + localId, currentSelection[i]); } #endif } } if (isFocusingUnused) { RefUnUse.ResetUnusedAsset(settings.recursiveUnusedScan); } } internal void SetFR2Selection(UnityObject[] objects) { selection?.SetUnityObjects(objects); // Only refresh FR2 view if cache is ready - this prevents errors but keeps selection updated if (AssetFinderCache.isReady) { RefreshFR2View(); } else { AssetFinderLOG.Log("Cache not ready - selection updated but view refresh skipped in SetFR2Selection"); } } internal UnityObject[] GetFR2Selection() { return selection?.GetUnityObjects() ?? Array.Empty(); } private void RefreshFR2View() { OnPanelSelectionChanged(); // Only refresh selection view if we have a selection object if (selection != null) { selection.RefreshView(); } // Refresh contextual messages based on current selection if (this is AssetFinderWindowAll window) { window.RefreshContextualMessages(); } ids = Array.Empty(); RefreshPanelVisible(); if (selection.isSelectingSceneObject) { // Get GameObjects from selection's instance IDs var gameObjects = new List(); foreach (string instIdStr in selection.instSet) { if (int.TryParse(instIdStr, out int instId)) { var obj = EditorUtility.InstanceIDToObject(instId); if (obj != null) gameObjects.Add(obj); } } RefSceneInScene.ResetSceneInScene(gameObjects.OfType().ToArray()); SceneToAssetDrawer.Reset(gameObjects.OfType().ToArray(), true, true); SceneUsesDrawer.ResetSceneUseSceneObjects(gameObjects.OfType().ToArray()); } else if (selection.isSelectingAsset) { ids = selection.guidSet.ToArray(); // These are the key calls that refresh the Uses/Used By tabs UsesDrawer.Reset(ids, true); UsedByDrawer.Reset(ids, false); RefInScene.Reset(ids); AddressableDrawer.RefreshView(); } } #if UNITY_2018_OR_NEWER private void OnSceneChanged(Scene arg0, Scene arg1) { if (IsFocusingFindInScene || IsFocusingSceneToAsset || IsFocusingSceneInScene) { OnSelectionChange(); } } #endif } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Window/AssetFinderWindowAll.SelectionManager.cs.meta ================================================ fileFormatVersion: 2 guid: d230407d4a38fca4aac642e7347be015 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Window/AssetFinderWindowAll.SettingsPanel.cs ================================================ using System; using System.Collections.Generic; using UnityEditor; using UnityEngine; using UnityObject = UnityEngine.Object; namespace VirtueSky.AssetFinder.Editor { internal partial class AssetFinderWindowAll { private void DrawSettings() { if (bottomTabs == null || bottomTabs.current == -1) return; GUILayout.BeginVertical(AssetFinderTheme.Current.SettingsPanelHeight); { GUILayout.Space(2f); switch (bottomTabs.current) { case 0: { DrawMainSettings(); break; } case 1: { DrawIgnoreSettings(); break; } case 2: { DrawFilterSettings(); break; } } } GUILayout.EndVertical(); Rect rect = GUILayoutUtility.GetLastRect(); rect.height = 1f; GUI2.Rect(rect, Color.black, 0.4f); } private void DrawMainSettings() { AssetFinderSetting.s.DrawSettings(); // Add the Write Import Log toggle in the settings GUILayout.Space(5f); EditorGUILayout.LabelField("Advanced Settings", EditorStyles.boldLabel); bool writeLog = settings.writeImportLog; settings.writeImportLog = EditorGUILayout.Toggle("Write Import Log", settings.writeImportLog); if (writeLog != settings.writeImportLog) { EditorUtility.SetDirty(this); } // Add Git settings if applicable if (AssetFinderSettingExt.isGitProject) { DrawGitSettings(); } } private void DrawGitSettings() { GUILayout.Space(5f); EditorGUILayout.LabelField("Git Settings", EditorStyles.boldLabel); if (AssetFinderSettingExt.gitIgnoreAdded) { EditorGUILayout.HelpBox("AssetFinderCache.asset* is already in your .gitignore file.", MessageType.Info); } else { EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Add AssetFinderCache.asset* to .gitignore"); if (GUILayout.Button("Apply", AssetFinderTheme.Current.ApplyButtonWidth)) { AssetFinderGitUtil.AddFR2CacheToGitIgnore(); AssetFinderSettingExt.gitIgnoreAdded = true; AssetFinderSettingExt.hideGitIgnoreWarning = true; } EditorGUILayout.EndHorizontal(); } } private void DrawIgnoreSettings() { if (AssetFinderAssetGroupDrawer.DrawIgnoreFolder()) { MarkDirty(); } } private void DrawFilterSettings() { if (AssetFinderAssetGroupDrawer.DrawSearchFilter()) { MarkDirty(); } } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Window/AssetFinderWindowAll.SettingsPanel.cs.meta ================================================ fileFormatVersion: 2 guid: 3eceec0c15546f04e9d2c65d68a93449 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Window/AssetFinderWindowAll.ToolsPanel.cs ================================================ using System; using System.Collections.Generic; using UnityEditor; using UnityEngine; using UnityObject = UnityEngine.Object; namespace VirtueSky.AssetFinder.Editor { internal partial class AssetFinderWindowAll { private AssetFinderDeleteButton deleteUnused; private void DrawTools() { if (isFocusingDuplicate) { Duplicated.DrawLayout(); GUILayout.FlexibleSpace(); return; } if (isFocusingUnused) { DrawUnusedAssetsPanel(); return; } if (isFocusingUsedInBuild) { UsedInBuild.DrawLayout(); return; } if (isFocusingOthers) { DrawOthersPanel(); return; } if (isFocusingGUIDs) { DrawGUIDs(); } } private void DrawUnusedAssetsPanel() { EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Recursive Search", AssetFinderTheme.Current.RecursiveSearchLabelWidth); bool oldRecursive = settings.recursiveUnusedScan; settings.recursiveUnusedScan = EditorGUILayout.Toggle(settings.recursiveUnusedScan, AssetFinderTheme.Current.ToggleWidth); if (oldRecursive != settings.recursiveUnusedScan) { RefUnUse.ResetUnusedAsset(settings.recursiveUnusedScan); EditorUtility.SetDirty(this); } EditorGUILayout.EndHorizontal(); if ((RefUnUse.refs != null) && (RefUnUse.refs.Count == 0)) { EditorGUILayout.HelpBox("Clean! Your project does not has have any unused assets!", MessageType.Info); GUILayout.FlexibleSpace(); EditorGUILayout.HelpBox("Your deleted assets was backup at Library/FR2/ just in case you want your assets back!", MessageType.Info); } else { RefUnUse.DrawLayout(); if (deleteUnused == null) { deleteUnused = new AssetFinderDeleteButton { warningMessage = "A backup (.unitypackage) will be created so you can reimport the deleted assets later!", deleteLabel = AssetFinderGUIContent.From("DELETE ASSETS", AssetFinderIcon.Delete.image), confirmMessage = "Create backup at Library/FR2/" }; } GUILayout.BeginHorizontal(); { deleteUnused.Draw(() => { AssetFinderUnity.BackupAndDeleteAssets(RefUnUse.source); }); } GUILayout.EndHorizontal(); } } private void DrawOthersPanel() { GUILayout.Space(4f); EditorGUILayout.BeginHorizontal(); // Left: Vertical tab bar EditorGUILayout.BeginVertical(AssetFinderTheme.Current.TabPanelWidth); var tabStyle = new GUIStyle(EditorStyles.toolbarButton) { alignment = TextAnchor.MiddleLeft, fixedHeight = 32f, fontStyle = FontStyle.Normal }; Color origColor = GUI.backgroundColor; for (var i = 0; i < 3; i++) { string label = i == 0 ? "Missing Scripts" : i == 1 ? "Organize Assets" : "Delete Empty Folders"; GUI.backgroundColor = (settings.othersTabIndex == i) ? new Color(0.7f, 0.9f, 1f, 1f) : origColor; if (GUILayout.Toggle(settings.othersTabIndex == i, label, tabStyle)) { if (settings.othersTabIndex != i) { settings.othersTabIndex = i; WillRepaint = true; } } } GUILayout.FlexibleSpace(); GUI.backgroundColor = origColor; EditorGUILayout.EndVertical(); // Right: Tool content EditorGUILayout.BeginVertical(); if (settings.othersTabIndex == 0) { MissingReference.DrawLayout(); } else if (settings.othersTabIndex == 1) { AssetOrganizer.DrawLayout(); } else { DeleteEmptyFolder.DrawLayout(); } EditorGUILayout.EndVertical(); EditorGUILayout.EndHorizontal(); } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Window/AssetFinderWindowAll.ToolsPanel.cs.meta ================================================ fileFormatVersion: 2 guid: 8a335a62fc282164b839db996dbc66c0 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Window/AssetFinderWindowAll.UILayout.cs ================================================ using System; using System.Collections.Generic; using UnityEditor; using UnityEngine; using UnityObject = UnityEngine.Object; namespace VirtueSky.AssetFinder.Editor { internal partial class AssetFinderWindowAll { internal AssetFinderRefDrawer[] _allDrawersCache; private void OnCSVClickExtension() { AssetFinderRef[] csvSource = null; AssetFinderRefDrawer drawer = GetAssetDrawer(); if (drawer != null) csvSource = drawer.source; if (isFocusingUnused && (csvSource == null)) csvSource = RefUnUse.source; if (isFocusingUsedInBuild && (csvSource == null)) csvSource = AssetFinderRef.FromDict(UsedInBuild.refs); if (isFocusingDuplicate && (csvSource == null)) csvSource = AssetFinderRef.FromList(Duplicated.list); AssetFinderExport.ExportCSV(csvSource); } private void RefreshPanelVisible() { if (sp2 == null) InitIfNeeded(); if (sp2 == null) return; sp2.splits[0].visible = isScenePanelVisible; sp2.splits[1].visible = isAssetPanelVisible; sp2.splits[2].visible = isFocusingAddressable; sp2.CalculateWeight(); } private void RefreshShowFullPath() { if (_allDrawersCache != null) { foreach (var drawer in _allDrawersCache) { if (drawer != null && drawer.Config != null) drawer.Config.showFullPath = settings.showFullPath; } } } private void RefreshShowFileSize() { if (_allDrawersCache != null) { foreach (var drawer in _allDrawersCache) { if (drawer != null && drawer.AssetConfig != null) drawer.AssetConfig.showFileSize = settings.showFileSize; } } } private void RefreshShowFileExtension() { if (_allDrawersCache == null) return; foreach (var drawer in _allDrawersCache) { if (drawer != null && drawer.AssetConfig != null) drawer.AssetConfig.showExtension = settings.showFileExtension; } } private void MarkDirty() { if (_allDrawersCache != null) { foreach (var drawer in _allDrawersCache) { drawer?.SetDirty(); } } Duplicated.SetDirty(); UsedInBuild.SetDirty(); AddressableDrawer.RefreshSort(); WillRepaint = true; } private void RefreshSort() { if (_allDrawersCache != null) { foreach (var drawer in _allDrawersCache) { drawer?.RefreshSort(); } } AddressableDrawer.RefreshSort(); Duplicated.RefreshSort(); UsedInBuild.RefreshSort(); // Ensure tool-specific drawers are also refreshed if (settings.toolMode) { RefUnUse?.RefreshSort(); } } private AssetFinderRefDrawer GetAssetDrawer() { if (isFocusingUses) return IsSelectingAssets ? UsesDrawer : SceneToAssetDrawer; if (isFocusingUsedBy) return IsSelectingAssets ? UsedByDrawer : null; if (isFocusingAddressable) return AddressableDrawer.drawer; return null; } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Window/AssetFinderWindowAll.UILayout.cs.meta ================================================ fileFormatVersion: 2 guid: 1201bb63b0c94244a85cfeb56f797f20 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Window/AssetFinderWindowAll.cs ================================================ using System; using System.Collections.Generic; using System.IO; using System.Linq; using UnityEditor; using UnityEngine; using UnityObject = UnityEngine.Object; namespace VirtueSky.AssetFinder.Editor { internal partial class AssetFinderWindowAll : AssetFinderWindowBase, IHasCustomMenu { [SerializeField] internal PanelSettings settings = new PanelSettings(); [MenuItem("Sunflower/Asset Finder/Show Window %#K")] internal static void ShowWindow() { var _window = CreateInstance(); _window.InitIfNeeded(); AssetFinderUnity.SetWindowTitle(_window, "Asset Finder"); _window.Show(); } [NonSerialized] internal AssetFinderBookmark bookmark; [NonSerialized] internal AssetFinderSelection selection; [NonSerialized] internal AssetFinderUsedInBuild UsedInBuild; [NonSerialized] internal AssetFinderDuplicateTree2 Duplicated; [NonSerialized] internal AssetFinderRefDrawer RefUnUse; [NonSerialized] internal AssetFinderMissingReference MissingReference; [NonSerialized] internal AssetFinderAssetOrganizer AssetOrganizer; [NonSerialized] internal AssetFinderDeleteEmptyFolder DeleteEmptyFolder; [NonSerialized] internal AssetFinderRefDrawer UsesDrawer; // [Selected Assets] are [USING] (depends on / contains reference to) ---> those assets [NonSerialized] internal AssetFinderRefDrawer UsedByDrawer; // [Selected Assets] are [USED BY] <---- those assets [NonSerialized] internal AssetFinderRefDrawer SceneToAssetDrawer; // [Selected GameObjects in current Scene] are [USING] ---> those assets [NonSerialized] internal AssetFinderAddressableDrawer AddressableDrawer; [NonSerialized] internal AssetFinderRefDrawer RefInScene; // [Selected Assets] are [USED BY] <---- those components in current Scene [NonSerialized] internal AssetFinderRefDrawer SceneUsesDrawer; // [Selected GameObjects] are [USING] ---> those components / GameObjects in current scene [NonSerialized] internal AssetFinderRefDrawer RefSceneInScene; // [Selected GameObjects] are [USED BY] <---- those components / GameObjects in current scene [NonSerialized] internal AssetFinderSmartLock smartLock = new AssetFinderSmartLock(); [NonSerialized] private AssetFinderNavigationHistory navigationHistory = new AssetFinderNavigationHistory(); // AssetFinderTheme singleton provides centralized UI constants [NonSerialized] internal AssetFinderTheme theme; // Simple flag to track selection sync status for UI highlighting [NonSerialized] internal bool isSelectionOutOfSync; // Cached contextual messages for drawers [NonSerialized] private string cachedUsesMessage; [NonSerialized] private string cachedUsedByMessage; [NonSerialized] private string cachedRefInSceneMessage; [NonSerialized] private string cachedSceneUsesMessage; [NonSerialized] private string cachedSceneToAssetMessage; [NonSerialized] private string cachedSceneInSceneMessage; [NonSerialized] private UnityObject[] lastCachedSelection; private string GetSceneContextInfo() { #if UNITY_2021_2_OR_NEWER // Unity 2021.2+ moved PrefabStageUtility to UnityEditor.SceneManagement var prefabStage = UnityEditor.SceneManagement.PrefabStageUtility.GetCurrentPrefabStage(); if (prefabStage != null) { string prefabName = System.IO.Path.GetFileNameWithoutExtension(prefabStage.assetPath); return $"current Prefab ({prefabName})"; } #elif UNITY_2018_3_OR_NEWER // Unity 2018.3 - 2021.1 had PrefabStageUtility in UnityEditor.Experimental.SceneManagement var prefabStage = UnityEditor.Experimental.SceneManagement.PrefabStageUtility.GetCurrentPrefabStage(); if (prefabStage != null) { #if UNITY_2020_1_OR_NEWER string prefabName = System.IO.Path.GetFileNameWithoutExtension(prefabStage.assetPath); #else string prefabName = System.IO.Path.GetFileNameWithoutExtension(prefabStage.prefabAssetPath); #endif return $"current Prefab ({prefabName})"; } #endif // Check scene count int sceneCount = UnityEngine.SceneManagement.SceneManager.sceneCount; if (sceneCount == 0) { return "current scene"; } else if (sceneCount == 1) { var scene = UnityEngine.SceneManagement.SceneManager.GetActiveScene(); if (scene.IsValid() && !string.IsNullOrEmpty(scene.name)) { return $"current scene ({scene.name})"; } return "current scene"; } else { return "current scenes"; // Multiple scenes } } public void Reload() { InitializeComponents(); } private GUIContent GetScenePanelTitle() { string titleText = "Scene"; string tooltip = "Scene references"; // Check scene status for title text modifications if (AssetFinderSceneCache.Api != null) { switch (AssetFinderSceneCache.Api.Status) { case SceneCacheStatus.Scanning: int cur = AssetFinderSceneCache.Api.current; int total = AssetFinderSceneCache.Api.total; if (total > 0) { titleText += $" (scanning {cur}/{total})"; tooltip = $"Currently scanning scene objects: {cur} of {total}"; } else { titleText += " (scanning...)"; tooltip = "Currently scanning scene objects"; } break; case SceneCacheStatus.None: titleText += " (not ready)"; tooltip = "Scene cache is not initialized"; break; case SceneCacheStatus.Changed: tooltip = "Scene changed - results might be incomplete"; break; case SceneCacheStatus.Ready: tooltip = "Scene cache ready"; break; } } return new GUIContent(titleText, AssetFinderIcon.Scene.image, tooltip); } private GUIContent GetAssetPanelTitle() { string titleText = "Assets"; string tooltip = "Asset references"; // Check asset status for title text modifications if (AssetFinderCache.Api == null) return new GUIContent(titleText, AssetFinderIcon.Asset.image, tooltip); if (!AssetFinderCache.isReady) { titleText += " (processing...)"; tooltip = $"Processing assets: {(AssetFinderCache.Api.progress * 100):F0}%"; } else if (AssetFinderCache.Api.HasChanged) { tooltip = "Assets changed - cache needs refresh"; } else if (AssetFinderCache.Api.workCount > 0) { tooltip = "Processing assets in background"; } else if (HasUnscannedAssets()) { tooltip = "Some assets not scanned yet - refresh cache to scan"; } else { tooltip = "Asset cache ready"; } return new GUIContent(titleText, AssetFinderIcon.Asset.image, tooltip); } private bool ScenePanelHasContent() { if (!AssetFinderSceneCache.hasCache) return false; // Check if scene panel would have content based on current selection AssetFinderRefDrawer drawer = isFocusingUses ? IsSelectingAssets ? null : SceneUsesDrawer : IsSelectingAssets ? RefInScene : RefSceneInScene; return drawer != null && drawer.source != null && drawer.source.Length > 0; } private bool AssetPanelHasContent() { if (!AssetFinderCache.isReady) return false; // Check if asset panel would have content based on current selection AssetFinderRefDrawer drawer = GetAssetDrawer(); return drawer != null && drawer.source != null && drawer.source.Length > 0; } private bool BookmarkPanelHasContent() { return bookmark != null && AssetFinderBookmark.Count > 0; } private bool IsScenePanelDirty() { if (AssetFinderSceneCache.Api == null) return false; // Show yellow title for various scene issues return AssetFinderSceneCache.Api.Status == SceneCacheStatus.Changed || AssetFinderSceneCache.Api.Status == SceneCacheStatus.None || AssetFinderSceneCache.Api.Status == SceneCacheStatus.Scanning; } private bool IsAssetPanelDirty() { if (AssetFinderCache.Api == null) return false; // Show yellow title when: // 1. Cache is not ready (still processing) // 2. Has pending changes that need refresh // 3. Has work in progress // 4. Has unscanned assets (never been processed) return !AssetFinderCache.isReady || AssetFinderCache.Api.HasChanged || AssetFinderCache.Api.workCount > 0 || HasUnscannedAssets(); } private bool HasUnscannedAssets() { if (AssetFinderCache.Api?.AssetList == null) return false; // Check if there are any critical assets that have never been scanned // Since folders are no longer in AssetList, we only check scannable assets foreach (var asset in AssetFinderCache.Api.AssetList) { if (asset.IsCriticalAsset() && !asset.hasBeenScanned) { return true; } } return false; } private string GetSceneStatusMessage() { if (AssetFinderSceneCache.Api == null) return null; switch (AssetFinderSceneCache.Api.Status) { case SceneCacheStatus.Changed: return "Scene changed - results might be incomplete"; case SceneCacheStatus.Scanning: return "Scanning scene objects..."; case SceneCacheStatus.None: return "Scene cache not ready"; default: return null; } } private string GetAssetStatusMessage() { if (AssetFinderCache.Api == null) return null; if (AssetFinderCache.Api.HasChanged) { return "Assets changed - cache needs refresh"; } else if (AssetFinderCache.Api.workCount > 0) { return $"Processing {AssetFinderCache.Api.workCount} assets..."; } else if (!AssetFinderCache.isReady) { return "Asset cache not ready"; } return null; } protected bool lockSelection => (selection != null) && selection.isLock; // Helper properties to access unified selection manager private bool IsSelectingAssets => selection?.isSelectingAsset ?? false; private bool IsSelectingSceneObjects => selection?.isSelectingSceneObject ?? false; private bool IsSelectionOutOfSync { get { if (selection == null) return false; var unitySelection = AssetFinderSelectionManager.Instance.GetUnitySelection(); var fr2Selection = selection.GetUnityObjects(); // Check count difference if (unitySelection.Length != fr2Selection.Length) return true; // Check content difference (order doesn't matter for warning) var unitySet = new HashSet(unitySelection); var fr2Set = new HashSet(fr2Selection); return !unitySet.SetEquals(fr2Set); } } private void RefreshContextualMessages() { var currentSelection = GetFR2Selection(); // Only regenerate if selection actually changed if (AreSelectionsEqual(lastCachedSelection, currentSelection)) return; lastCachedSelection = currentSelection; cachedUsesMessage = GenerateContextualMessage(currentSelection, "USING"); cachedUsedByMessage = GenerateContextualMessage(currentSelection, "USED BY"); cachedRefInSceneMessage = GenerateContextualMessage(currentSelection, "USED BY", " any GameObjects in current scene"); cachedSceneUsesMessage = GenerateContextualMessage(currentSelection, "USING", " any other objects"); cachedSceneToAssetMessage = GenerateContextualMessage(currentSelection, "USING", " any assets"); cachedSceneInSceneMessage = GenerateContextualMessage(currentSelection, "USED BY", " any other GameObjects"); } private void ClearAllCachedUIElements() { // Clear cached contextual messages cachedUsesMessage = null; cachedUsedByMessage = null; cachedRefInSceneMessage = null; cachedSceneUsesMessage = null; cachedSceneToAssetMessage = null; cachedSceneInSceneMessage = null; lastCachedSelection = null; } private string GenerateContextualMessage(UnityObject[] objects, string action, string suffix = " any other assets") { if (objects == null || objects.Length == 0) return $"Nothing selected is {action}{suffix}!"; // Replace "current scene" with contextual info for scene-related messages if (suffix.Contains("current scene")) { suffix = suffix.Replace("current scene", GetSceneContextInfo()); } // Check if any selected assets are ignored var ignoredAssets = new List(); var nonIgnoredAssets = new List(); foreach (var obj in objects) { if (AssetDatabase.Contains(obj)) { string assetPath = AssetDatabase.GetAssetPath(obj); bool isIgnored = AssetFinderSetting.IgnoreAsset.Any(ignore => assetPath.Equals(ignore, StringComparison.OrdinalIgnoreCase) || assetPath.StartsWith(ignore + "/", StringComparison.OrdinalIgnoreCase)); if (isIgnored) ignoredAssets.Add(obj.name); else nonIgnoredAssets.Add(obj); } else { nonIgnoredAssets.Add(obj); } } // If all selected assets are ignored, show special message if (ignoredAssets.Count > 0 && nonIgnoredAssets.Count == 0) { if (objects.Length == 1) { return $"{objects[0].name} is in the ignore list and won't show references!"; } else { return $"All {objects.Length} selected assets are in the ignore list and won't show references!"; } } // If some are ignored, show mixed message if (ignoredAssets.Count > 0) { string baseMessage = GenerateBasicMessage(nonIgnoredAssets.ToArray(), action, suffix); return $"{baseMessage} ({ignoredAssets.Count} ignored asset{(ignoredAssets.Count > 1 ? "s" : "")} not shown)"; } // Normal case - no ignored assets return GenerateBasicMessage(objects, action, suffix); } private string GenerateBasicMessage(UnityObject[] objects, string action, string suffix) { if (objects == null || objects.Length == 0) return $"Nothing selected is {action}{suffix}!"; // Check if this is a scene-related message - skip asset scan status for scene references bool isSceneRelated = suffix.Contains("GameObjects") || suffix.Contains("other objects"); if (objects.Length == 1) { var obj = objects[0]; string name = obj.name; string typeName = GetFriendlyTypeName(obj); bool isAsset = AssetDatabase.Contains(obj); if (isAsset) { string assetPath = AssetDatabase.GetAssetPath(obj); if (Directory.Exists(assetPath)) { return $"{name} does not use any other assets!"; } // Check if this asset is non-critical (ignored, packages, built-in) string guid = AssetDatabase.AssetPathToGUID(assetPath); var asset = AssetFinderCache.Api?.Get(guid); // bool isPackageAsset = assetPath.StartsWith("Packages/"); bool isIgnoredAsset = AssetFinderSetting.IgnoreAsset.Any(ignore => assetPath.Equals(ignore, StringComparison.OrdinalIgnoreCase) || assetPath.StartsWith(ignore + "/", StringComparison.OrdinalIgnoreCase)); bool isBuiltInAsset = asset != null && AssetFinderAsset.BUILT_IN_ASSETS.Contains(asset.guid); bool isNonCritical = asset != null && !asset.IsCriticalAsset(); // For "USING" tab - show special message for non-critical assets if (action == "USING" && (isIgnoredAsset || isBuiltInAsset || isNonCritical)) { // if (isPackageAsset) // return $"{name} usage is skipped (Package asset)"; if (isIgnoredAsset) return $"{name} usage is skipped (Ignored asset)"; if (isBuiltInAsset) return $"{name} usage is skipped (Built-in asset)"; return $"{name} usage is skipped (Non-critical asset)"; } // For "USED BY" tab - never show content scan messages, only show if truly no references if (action == "USED BY") { return $"{name} is not {action}{suffix}!"; } // Skip asset scan status checks for scene-related messages if (!isSceneRelated) { var assetStatus = GetAssetScanStatus(assetPath); if (assetStatus.isNonScannable) { return $"{name} does not use any other assets!"; } if (assetStatus.needsScanning) { return $"{name} not scanned yet - hit Refresh for complete results!"; } if (assetStatus.isDirty) { return $"{name} content changed - hit Refresh for complete results!"; } } return $"{name} is not {action}{suffix}!"; } else { return $"{typeName} '{name}' is not {action}{suffix}!"; } } else { string selectionSummary = GenerateSelectionSummary(objects); // For "USED BY" tab with multiple assets - never show content scan messages if (action == "USED BY") { return $"{selectionSummary} are not {action}{suffix}!"; } // Skip asset scan status checks for scene-related messages if (!isSceneRelated) { var scanStatus = GetMultipleAssetsScanStatus(objects); if (scanStatus.allUnscanned) { return $"{selectionSummary} not scanned yet - hit Refresh for complete results!"; } else if (scanStatus.allDirty) { return $"{selectionSummary} content changed - hit Refresh for complete results!"; } else if (scanStatus.hasMixed) { return $"{selectionSummary} need scanning - hit Refresh for complete results!"; } } return $"{selectionSummary} are not {action}{suffix}!"; } } private string GenerateSelectionSummary(UnityObject[] objects) { var typeCounts = new Dictionary(); foreach (var obj in objects) { string typeName = GetFriendlyTypeName(obj); if (typeCounts.ContainsKey(typeName)) typeCounts[typeName]++; else typeCounts[typeName] = 1; } // Sort by count (descending) then by name for consistent ordering var sortedTypes = typeCounts.OrderByDescending(kvp => kvp.Value) .ThenBy(kvp => kvp.Key) .ToList(); if (sortedTypes.Count == 1) { var kvp = sortedTypes[0]; return $"{kvp.Value} selected {GetPluralTypeName(kvp.Key, kvp.Value)}"; } else if (sortedTypes.Count <= 3) { // Show up to 3 types: "2 Materials, 1 Texture2D, 3 GameObjects" var parts = sortedTypes.Select(kvp => $"{kvp.Value} {GetPluralTypeName(kvp.Key, kvp.Value)}"); return string.Join(", ", parts); } else { // Too many types, show total count: "15 selected objects" return $"{objects.Length} selected objects"; } } private string GetFriendlyTypeName(UnityObject obj) { if (obj == null) return "Unknown"; // Special cases for better names var type = obj.GetType(); string typeName = type.Name; // Handle common Unity types with better names switch (typeName) { case "Texture2D": return "Texture2D"; case "Material": return "Material"; case "AudioClip": return "Audio Clip"; case "GameObject": return "GameObject"; case "MonoScript": return "Script"; case "DefaultAsset": // For folders and other default assets if (AssetDatabase.IsValidFolder(AssetDatabase.GetAssetPath(obj))) return "Folder"; return "Asset"; case "Sprite": return "Sprite"; case "Mesh": return "Mesh"; case "Shader": return "Shader"; case "AnimationClip": return "Animation"; case "Cubemap": return "Cubemap"; case "Font": return "Font"; case "TextAsset": return "Text Asset"; case "ScriptableObject": return "Scriptable Object"; case "Prefab": return "Prefab"; default: // Clean up namespace if present if (typeName.Contains('.')) typeName = typeName.Substring(typeName.LastIndexOf('.') + 1); return typeName; } } private string GetPluralTypeName(string typeName, int count) { if (count <= 1) return typeName; // Handle specific pluralization rules switch (typeName.ToLower()) { case "gameobject": return "GameObjects"; case "material": return "Materials"; case "texture2d": return "Texture2Ds"; case "audio clip": return "Audio Clips"; case "script": return "Scripts"; case "folder": return "Folders"; case "sprite": return "Sprites"; case "mesh": return "Meshes"; case "shader": return "Shaders"; case "animation": return "Animations"; case "cubemap": return "Cubemaps"; case "font": return "Fonts"; case "text asset": return "Text Assets"; case "scriptable object": return "Scriptable Objects"; case "prefab": return "Prefabs"; default: // Generic pluralization - just add 's' return typeName + "s"; } } private (bool isNonScannable, bool needsScanning, bool isDirty) GetAssetScanStatus(string assetPath) { string guid = AssetDatabase.AssetPathToGUID(assetPath); if (!AssetFinderCache.isReady || AssetFinderCache.Api == null) return (false, false, false); var asset = AssetFinderCache.Api.Get(guid, true); if (asset == null) return (false, false, false); bool isNonScannable = asset.type == AssetFinderAsset.AssetType.DLL || asset.type == AssetFinderAsset.AssetType.SCRIPT || asset.type == AssetFinderAsset.AssetType.NON_READABLE || !asset.IsCriticalAsset(); bool needsScanning = !asset.hasBeenScanned; bool isDirty = asset.isDirty; // Debug.Log($"GetAssetScanStatus: {assetPath} -->\n isNonScannable: {isNonScannable} | needScanning: {needsScanning} | isDirty = {asset.isDirty}"); return (isNonScannable, needsScanning && !isNonScannable, isDirty && !isNonScannable); } private (bool allUnscanned, bool allDirty, bool hasMixed) GetMultipleAssetsScanStatus(UnityObject[] objects) { if (!AssetFinderCache.isReady || AssetFinderCache.Api == null) return (false, false, false); bool hasUnscannedAssets = false; bool hasDirtyAssets = false; bool hasRegularAssets = false; foreach (var obj in objects) { if (!AssetDatabase.Contains(obj)) continue; string assetPath = AssetDatabase.GetAssetPath(obj); string guid = AssetDatabase.AssetPathToGUID(assetPath); var asset = AssetFinderCache.Api.Get(guid, true); if (asset == null) continue; bool isNonScannable = asset.type == AssetFinderAsset.AssetType.DLL || asset.type == AssetFinderAsset.AssetType.SCRIPT || asset.type == AssetFinderAsset.AssetType.NON_READABLE || !asset.IsCriticalAsset(); if (isNonScannable) { hasRegularAssets = true; continue; } bool neverScanned = !asset.hasBeenScanned; bool isDirty = asset.isDirty; if (neverScanned) hasUnscannedAssets = true; else if (isDirty) hasDirtyAssets = true; else hasRegularAssets = true; } bool allUnscanned = hasUnscannedAssets && !hasDirtyAssets && !hasRegularAssets; bool allDirty = hasDirtyAssets && !hasUnscannedAssets && !hasRegularAssets; bool hasMixed = (hasUnscannedAssets || hasDirtyAssets) && hasRegularAssets; return (allUnscanned, allDirty, hasMixed); } private static bool AreSelectionsEqual(UnityObject[] selection1, UnityObject[] selection2) { if (selection1 == null && selection2 == null) return true; if (selection1 == null || selection2 == null) return false; if (selection1.Length != selection2.Length) return false; var set1 = new HashSet(selection1); var set2 = new HashSet(selection2); return set1.SetEquals(set2); } private void OnEnable() { AssetFinderUnity.RefreshEditorStatus(); wantsMouseMove = true; // Initialize theme based on current Unity skin (needed because it's NonSerialized) theme = EditorGUIUtility.isProSkin ? AssetFinderTheme.Dark : AssetFinderTheme.Light; // Initialize selection manager early InitializeSelectionManager(); RegisterSceneCacheCallbacks(); AssetFinderCache.onReady -= OnAssetCacheReady; AssetFinderCache.onReady += OnAssetCacheReady; UpdateSceneCacheAutoRefresh(); Repaint(); } private void OnDisable() { UnregisterSceneCacheCallbacks(); OnDisableSelectionManager(); // Cleanup selection event subscription if (selection != null) { selection.OnSelectionChanged -= OnLocalSelectionChanged; } AssetFinderCache.onReady -= OnAssetCacheReady; } private void OnFocus() { AssetFinderUnity.RefreshEditorStatus(); } private void RegisterSceneCacheCallbacks() { AssetFinderSceneCache.onReady -= OnSceneCacheReady; AssetFinderSceneCache.onReady += OnSceneCacheReady; } private void UnregisterSceneCacheCallbacks() { AssetFinderSceneCache.onReady -= OnSceneCacheReady; } private void OnSceneCacheReady() { WillRepaint = true; // Clear cached UI elements when scene cache is refreshed ClearAllCachedUIElements(); // Always refresh FR2 panels when scene cache finishes scanning // This ensures Uses/UsedBy panels show updated results for current selection RefreshFR2View(); // If selection was out of sync due to cache not being ready, sync now if (isSelectionOutOfSync && selection != null && !selection.isLock) { selection.SyncFromGlobalSelection(); RefreshFR2View(); isSelectionOutOfSync = false; } } private void OnAssetCacheReady() { WillRepaint = true; ClearAllCachedUIElements(); RefreshFR2View(); } private void UpdateSceneCacheAutoRefresh() { if (AssetFinderSceneCache.Api != null) AssetFinderSceneCache.Api.AutoRefresh = AssetFinderSettingExt.isAutoRefreshEnabled; } protected void InitIfNeeded() { if (UsesDrawer != null) return; InitializeComponents(); } private bool ValidateLockedSelection() { if (!lockSelection) return true; var currentFR2Selection = GetFR2Selection(); if (currentFR2Selection == null || currentFR2Selection.Length == 0) { UnlockAndSyncSelection(); return false; } var validObjects = currentFR2Selection.Where(obj => obj != null).ToArray(); if (validObjects.Length == 0) { UnlockAndSyncSelection(); RefreshFR2View(); return false; } if (validObjects.Length != currentFR2Selection.Length) { SetFR2Selection(validObjects); return true; } return true; } private void UnlockAndSyncSelection() { selection.isLock = false; selection.SyncFromGlobalSelection(); isSelectionOutOfSync = false; } private bool isScenePanelVisible { get { if (isFocusingAddressable) return false; if (IsSelectingAssets && isFocusingUses) return false; if (!IsSelectingAssets && isFocusingUsedBy) return true; return settings.scene; } } private bool isAssetPanelVisible { get { if (isFocusingAddressable) return false; if (IsSelectingAssets && isFocusingUses) return true; if (!IsSelectingAssets && isFocusingUsedBy) return false; return settings.asset; } } [NonSerialized] public AssetFinderSplitView sp1; // container : Selection / sp2 / Bookmark [NonSerialized] public AssetFinderSplitView sp2; // Scene / Assets [NonSerialized] private AssetFinderTabView tabs; [NonSerialized] private AssetFinderTabView toolTabs; [NonSerialized] private AssetFinderTabView bottomTabs; [NonSerialized] private AssetFinderSearchView search; private void DrawScene(Rect rect) { DrawScenePanel(rect); } private void DrawAsset(Rect rect) { DrawAssetPanel(rect); } private void DrawSearch() { if (search == null) search = new AssetFinderSearchView(); search.DrawLayout(); } private void DrawSelectionPanel(Rect rect) { if (selection == null) return; selection.Draw(rect); } private void DrawDetailsPanel(Rect rect) { var drawer = GetActiveDrawer(); if (drawer != null) { drawer.DrawDetails(rect); } else { EditorGUI.HelpBox(rect, "No details available - select an item in the main panel to see details", MessageType.Info); } } private AssetFinderRefDrawer GetActiveDrawer() { if (isFocusingUses) { return IsSelectingAssets ? UsesDrawer : SceneUsesDrawer; } else if (isFocusingUsedBy) { return IsSelectingAssets ? UsedByDrawer : RefSceneInScene; } return null; } protected override void OnGUI() { OnGUI2(); } internal void ToggleDetailsPanel() { settings.details = !settings.details; if (sp1 != null && sp1.splits != null && sp1.splits.Count > 2) { sp1.splits[2].visible = settings.details; sp1.CalculateWeight(); } Repaint(); } public bool isFocusingUses => tabs?.IsFocusing(0) ?? false; public bool isFocusingUsedBy => tabs?.IsFocusing(1) ?? false; public bool isFocusingAddressable => tabs?.IsFocusing(2) ?? false; // public bool isFocusingDuplicate => toolTabs?.IsFocusing(0) ?? false; public bool isFocusingGUIDs => toolTabs?.IsFocusing(1) ?? false; public bool isFocusingUnused => toolTabs?.IsFocusing(2) ?? false; public bool isFocusingUsedInBuild => toolTabs?.IsFocusing(3) ?? false; public bool isFocusingOthers => toolTabs?.IsFocusing(4) ?? false; private static readonly HashSet allowedModes = new HashSet { AssetFinderRefDrawer.Mode.Type, AssetFinderRefDrawer.Mode.Extension, AssetFinderRefDrawer.Mode.Folder }; private void OnTabChange() { if (deleteUnused != null) deleteUnused.hasConfirm = false; if (UsedInBuild != null) UsedInBuild.SetDirty(); // Fix: Refresh panel visibility when switching between Uses/Used By tabs RefreshPanelVisible(); // Force refresh drawers when tab changes to ensure content is displayed // Only skip if cache not ready or selection is null if (AssetFinderCache.isReady && selection != null) { RefreshFR2View(); } } protected bool DrawFooter() { bottomTabs.DrawLayout(); var bottomBar = GUILayoutUtility.GetLastRect(); bottomBar = bottomBar.LPad(theme.FooterButtonsOffset); // offset for left buttons var (fullPathRect, flex1) = bottomBar.ExtractLeft(theme.IconButtonSize); var (fileSizeRect, flex2) = flex1.ExtractLeft(theme.IconButtonSize); var (extensionRect, flex3) = flex2.ExtractLeft(theme.IconButtonSize); var (buttonRect, flex4) = flex3.ExtractRight(theme.IconButtonSize); var viewModeRect = flex4.RPad(theme.IconButtonSize).SetWidth(theme.ViewModeSelectorWidthValue); viewModeRect.x = flex4.xMax - 224f; DrawViewModes(viewModeRect); DrawButton(buttonRect, ref settings.toolMode, AssetFinderIcon.CustomTool); if (DrawButton(fullPathRect, ref settings.showFullPath, AssetFinderIcon.FullPath)) RefreshShowFullPath(); if (DrawButton(fileSizeRect, ref settings.showFileSize, AssetFinderIcon.Filesize)) RefreshShowFileSize(); if (DrawButton(extensionRect, ref settings.showFileExtension, AssetFinderIcon.FileExtension)) RefreshShowFileExtension(); return false; } // Save status to temp variable so the result will be consistent between Layout & Repaint internal static int delayRepaint; internal static bool checkDrawImportResult; protected void OnGUI2() { if (Event.current.type == EventType.Layout) { AssetFinderUnity.RefreshEditorStatus(); ValidateLockedSelection(); } if (Event.current.type == EventType.MouseMove || Event.current.type == EventType.ScrollWheel || Event.current.type == EventType.MouseLeaveWindow || Event.current.type == EventType.MouseEnterWindow) { WillRepaint = true; } if (AssetFinderSettingExt.disable) { DrawEnable(); return; } if (AssetFinderSettingExt.isAutoRefreshEnabled && !AssetFinderSceneCache.hasInit) AssetFinderSceneCache.Api.RefreshCache(true); UpdateSceneCacheAutoRefresh(); if (!AssetFinderCacheHelper.inited) AssetFinderCacheHelper.InitHelper(); var result = CheckDrawImport(); if (Event.current.type == EventType.Layout) checkDrawImportResult = result; if (!checkDrawImportResult) return; if (settings.toolMode) { if (!AssetFinderSettingExt.hideToolsWarning) { EditorGUILayout.BeginHorizontal(); EditorGUILayout.HelpBox(AssetFinderGUIContent.From( "Tools are POWERFUL & DANGEROUS! Only use if you know what you are doing!!!", AssetFinderIcon.Warning.image)); if (GUILayout.Button(" x", EditorStyles.label, theme.CloseButtonWidth, theme.WarningCloseButtonHeight)) AssetFinderSettingExt.hideToolsWarning = true; EditorGUILayout.EndHorizontal(); } DrawGitWarningPanel(); toolTabs.DrawLayout(); DrawTools(); } else { DrawGitWarningPanel(); tabs.DrawLayout(); sp1.DrawLayout(); StorePanelPixels(); } DrawSettings(); DrawFooter(); if (sp1.hasResize && Event.current.type == EventType.Repaint) { var selectionInfo = sp1.splits[0]; var detailsInfo = sp1.splits[2]; var bookmarkInfo = sp1.splits[3]; if (selectionInfo.visible) settings.selectionPanelPixel = Mathf.Max(selectionInfo.minPixel, selectionInfo.preferredPixel); if (detailsInfo.visible) settings.detailsPanelPixel = Mathf.Max(detailsInfo.minPixel, detailsInfo.preferredPixel); if (bookmarkInfo.visible) settings.bookmarkPanelPixel = Mathf.Max(bookmarkInfo.minPixel, bookmarkInfo.preferredPixel); EditorUtility.SetDirty(this); } if (!WillRepaint) return; WillRepaint = false; Repaint(); } private void StorePanelPixels() { if (sp1 == null || sp1.splits == null || sp1.splits.Count == 0) return; var selectionInfo = sp1.splits[0]; if (selectionInfo.visible) { settings.selectionPanelPixel = Mathf.Max(selectionInfo.minPixel, selectionInfo.rect.width); } if (sp1.splits.Count > 2) { var detailsInfo = sp1.splits[2]; if (detailsInfo.visible) { settings.detailsPanelPixel = Mathf.Max(detailsInfo.minPixel, detailsInfo.rect.width); } } if (sp1.splits.Count > 3) { var bookmarkInfo = sp1.splits[3]; if (bookmarkInfo.visible) { settings.bookmarkPanelPixel = Mathf.Max(bookmarkInfo.minPixel, bookmarkInfo.rect.width); } } } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Window/AssetFinderWindowAll.cs.meta ================================================ fileFormatVersion: 2 guid: 57d9cbcdaeab0d745953a66ddc225bd9 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Window/AssetFinderWindowBase.cs ================================================ using UnityEditor; using UnityEngine; namespace VirtueSky.AssetFinder.Editor { public abstract class AssetFinderWindowBase : EditorWindow, IWindow { public bool WillRepaint { get; set; } protected bool showFilter, showIgnore; //[NonSerialized] protected bool lockSelection; //[NonSerialized] internal List Selected; public void AddItemsToMenu(GenericMenu menu) { var api = AssetFinderCache.Api; if (api == null) return; menu.AddDisabledItem(AssetFinderGUIContent.FromString("AssetFinder - ref2.6.4")); menu.AddSeparator(string.Empty); menu.AddItem(AssetFinderGUIContent.FromString("Enable"), !AssetFinderSettingExt.disable, () => { AssetFinderSettingExt.disable = !AssetFinderSettingExt.disable; }); menu.AddItem(AssetFinderGUIContent.FromString($"Auto Refresh: {AssetFinderSettingExt.autoRefreshMode}"), AssetFinderSettingExt.isAutoRefreshEnabled, () => { AssetFinderSettingExt.autoRefreshMode = AssetFinderSettingExt.isAutoRefreshEnabled ? AssetFinderAutoRefreshMode.Off : AssetFinderAutoRefreshMode.On; if (AssetFinderSettingExt.autoRefreshMode == AssetFinderAutoRefreshMode.On) { AssetFinderCache.Api.IncrementalRefresh(); } }); menu.AddItem(AssetFinderGUIContent.FromString($"Refresh"), false, () => { AssetFinderCache.Api.ClearCacheCompletely(); AssetFinderCache.Api.Check4Changes(true); }); menu.AddSeparator(string.Empty); // Developer mode toggle bool isDebugMode = AssetFinderDefine.IsDebugModeEnabled(); menu.AddItem(AssetFinderGUIContent.FromString($"Developer Mode"), isDebugMode, () => { AssetFinderDefine.ToggleDebugMode(!isDebugMode); }); AddToCustomMenu(menu); } public abstract void AddToCustomMenu(GenericMenu menu); public abstract void OnSelectionChange(); protected abstract void OnGUI(); #if UNITY_2018_OR_NEWER protected void OnSceneChanged(Scene arg0, Scene arg1) { if (IsFocusingFindInScene || IsFocusingSceneToAsset || IsFocusingSceneInScene) { OnSelectionChange(); } } #endif protected bool DrawEnable() { AssetFinderCache api = AssetFinderCache.Api; if (api == null) return false; if (!AssetFinderSettingExt.disable) return true; bool isPlayMode = EditorApplication.isPlayingOrWillChangePlaymode; string message = isPlayMode ? "Find References 2 is disabled in play mode!" : "Find References 2 is disabled!"; EditorGUILayout.HelpBox(AssetFinderGUIContent.From(message, AssetFinderIcon.Warning.image)); if (GUILayout.Button(AssetFinderGUIContent.FromString("Enable"))) { AssetFinderSettingExt.disable = !AssetFinderSettingExt.disable; if (!AssetFinderSettingExt.disable && AssetFinderCache.Api != null) { AssetFinderCache.Api.IncrementalRefresh(); } Repaint(); } return false; } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Window/AssetFinderWindowBase.cs.meta ================================================ fileFormatVersion: 2 guid: b0f5dd186be864a489cf1712d6297c5d MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Window/IRefDraw.cs ================================================ using UnityEngine; namespace VirtueSky.AssetFinder.Editor { internal interface IRefDraw { IWindow window { get; } int ElementCount(); bool DrawLayout(); bool Draw(Rect rect); } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Window/IRefDraw.cs.meta ================================================ fileFormatVersion: 2 guid: 8eabb463923a4f67b4e3e1ef63ec2bc4 timeCreated: 1746370625 ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Window/IWindow.cs ================================================ namespace VirtueSky.AssetFinder.Editor { public interface IWindow { bool WillRepaint { get; set; } void Repaint(); } } ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Window/IWindow.cs.meta ================================================ fileFormatVersion: 2 guid: 005f5270e708458d8f5e137822248058 timeCreated: 1746370637 ================================================ FILE: VirtueSky/AssetFinder/Editor/Script/Window.meta ================================================ fileFormatVersion: 2 guid: 283461c5abe8449f98f9b196b50d0e4b timeCreated: 1746366625 ================================================ FILE: VirtueSky/AssetFinder/Editor/Script.meta ================================================ fileFormatVersion: 2 guid: 9124b66e19b3c44bf999ad7566fa6450 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/Virtuesky.Sunflower.AssetFinder.Editor.asmdef ================================================ { "name": "Virtuesky.Sunflower.AssetFinder.Editor", "rootNamespace": "", "references": [ "Unity.Addressables", "Virtuesky.Sunflower.DataStorage.Editor", "VirtueSky.Sunflower.Inspector", "Unity.Addressables.Editor" ], "includePlatforms": [ "Editor" ], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], "versionDefines": [ { "name": "com.unity.addressables", "expression": "0.0.0", "define": "AssetFinderADDRESSABLE" }, { "name": "com.unity.visualeffectgraph", "expression": "0.0.0", "define": "ASSET_USAGE_VFX_GRAPH" } ], "noEngineReferences": false } ================================================ FILE: VirtueSky/AssetFinder/Editor/Virtuesky.Sunflower.AssetFinder.Editor.asmdef.meta ================================================ fileFormatVersion: 2 guid: 8579ab42c9ab63d4bac5fb07bd390b46 AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/AssetFinder.cs ================================================ using System.Collections.Generic; using System.IO; using UnityEditor; namespace VirtueSky.AssetFinder.Editor { internal class AssetFileInfo { public readonly string assetPath; public bool exists; public string fileExt; public string fileName; public long fileSize; public string folder; public AssetFileInfo(string guid) { assetPath = AssetDatabase.GUIDToAssetPath(guid) + "/"; fileName = Path.GetFileNameWithoutExtension(assetPath); fileExt = "." + Path.GetExtension(assetPath); if (string.IsNullOrWhiteSpace(assetPath)) { exists = false; return; } exists = File.Exists(assetPath); if (!exists) return; fileSize = new FileInfo(assetPath).Length; folder = Path.GetDirectoryName(assetPath); } } internal class AssetFolder { private static readonly Dictionary map = new Dictionary(); public string guid; public string path; public static AssetFolder Get(string guid) { return map.GetValueOrDefault(guid); } public static AssetFolder Create(string guid) { string path = AssetDatabase.GUIDToAssetPath(guid); if (string.IsNullOrEmpty(path)) return null; var folder = new AssetFolder { guid = guid, path = path }; map[guid] = folder; return folder; } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/AssetFinder.cs.meta ================================================ fileFormatVersion: 2 guid: f77ff3449563f4fccb4f9f89b2516c9a MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/Core/AssetFinderAssetDB.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using UnityEditor; using UnityEngine; namespace VirtueSky.AssetFinder.Editor { [Serializable] internal class AssetFinderAssetDB { [SerializeField] internal List files = new List(); [SerializeField] internal List refs = new List(); [NonSerialized] internal readonly Dictionary guidMap = new Dictionary(); [NonSerialized] internal bool isReady; [NonSerialized] internal AssetFinderTimeSlice readContentTS; internal AssetFinderAssetFile GetAssetByGUID(string guid) { return guidMap.GetValueOrDefault(guid); } private AssetFinderAssetFile AddAsset(string guid) { string assetPath = AssetDatabase.GUIDToAssetPath(guid); if (string.IsNullOrEmpty(assetPath)) return null; var assetFile = new AssetFinderAssetFile(guid, files.Count); guidMap.Add(guid, assetFile); files.Add(assetFile); return assetFile; } internal AssetFinderAssetFile GetAsset(AssetFinderID id) { return files[id.AssetIndex]; } internal AssetFinderAssetDB Clear() { files.Clear(); refs.Clear(); guidMap.Clear(); return this; } internal void Scan(bool force = false) { if (force) Clear(); string[] allAssetPaths = AssetDatabase.GetAllAssetPaths(); foreach (string path in allAssetPaths) { if (path.Contains("FindReference2") || path.Contains("AssetFinderCache")) continue; string guid = AssetDatabase.AssetPathToGUID(path); // if (path.StartsWith("Packages/", StringComparison.InvariantCulture)) // { // AssetFinderLOG.Log($"Skip assets in Packages: {guid} --> {path}"); // continue; // } if (AssetDatabase.IsValidFolder(path)) { AssetFinderLOG.Log($"Skip Folder: {guid} --> {path}"); continue; } if (AssetFinderParser.IsReadable(path)) AddAsset(guid); } ReadContent(); } internal void ReadContent() { int count = files.Count; if (readContentTS == null) readContentTS = new AssetFinderTimeSlice(() => count, TS_ReadFileContent, FinishReadContent); readContentTS.Start(); } void FinishReadContent() { // Save refs refs.Clear(); guidMap.Clear(); for (var i =0;i < files.Count; i++) { AssetFinderAssetFile assetFile = files[i]; guidMap.Add(assetFile.guid, assetFile); refs.AddRange(assetFile.usage); } isReady = true; } internal void BuildCache() { guidMap.Clear(); for (var i = 0; i < files.Count; i++) { AssetFinderAssetFile assetFile = files[i]; if (assetFile == null) continue; assetFile.fileIdMap.Clear(); foreach (long fileId in assetFile.fileIds.Distinct()) { assetFile.fileIdMap.Add(fileId, assetFile.fileIds.IndexOf(fileId)); } guidMap.Add(assetFile.guid, assetFile); assetFile.usage.Clear(); assetFile.usedBy.Clear(); } for (var i = 0; i < refs.Count; i++) { AssetFinderIDRef r = refs[i]; AssetFinderAssetFile from = GetAsset(r.fromId.WithoutSubAssetIndex()); AssetFinderAssetFile to = GetAsset(r.toId.WithoutSubAssetIndex()); if (from == null || to == null) { Debug.LogWarning($"Invalid reference (asset not found???): {r.fromId} --> {r.toId}"); continue; } from.usage.Add(r); to.usedBy.Add(r); } isReady = true; } internal void TS_ReadFileContent(int index) { AssetFinderAssetFile sourceFile = files[index]; string assetPath = AssetDatabase.GUIDToAssetPath(sourceFile.guid); if (string.IsNullOrEmpty(assetPath)) return; var usage = new HashSet(); AssetFinderParser.ReadContent(assetPath, (guid, fileId) => { if (guid == sourceFile.guid) return; // Skip self reference AssetFinderAssetFile destFile = GetAssetByGUID(guid) ?? AddAsset(guid); if (destFile == null) return; // Invalid or missing GUID??? int subAssetIndex = destFile.Get(fileId); if (subAssetIndex == -1) subAssetIndex = destFile.Add(fileId); AssetFinderID toFR2Id = destFile.fr2Id.WithSubAssetIndex(subAssetIndex); if (!usage.Add(toFR2Id)) return; // Already added var r = new AssetFinderIDRef() { fromId = sourceFile.fr2Id, toId = toFR2Id }; sourceFile.usage.Add(r); destFile.usedBy.Add(r); }); } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/Core/AssetFinderAssetDB.cs.meta ================================================ fileFormatVersion: 2 guid: 21cc30678bacede4d9a6013ff74557b3 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/Core/AssetFinderAssetFile.cs ================================================ using System; using System.Collections.Generic; using UnityEditor; using UnityEngine; using UnityObject = UnityEngine.Object; namespace VirtueSky.AssetFinder.Editor { [Serializable] internal class AssetFinderAssetFile { [SerializeField] internal AssetFinderID fr2Id; [SerializeField] internal string guid; [SerializeField] internal List fileIds = new List { 0 }; // Some assets has detail, some does not [SerializeField] internal List subDetails = new List(); // Cache [NonSerialized] internal readonly Dictionary fileIdMap = new Dictionary(); // map fileId => index [NonSerialized] internal readonly List usage = new List(); [NonSerialized] internal readonly List usedBy = new List(); public AssetFinderAssetFile() { } public AssetFinderAssetFile(string guid, int assetIndex) { this.guid = guid; fr2Id = new AssetFinderID(assetIndex, 0, false); } internal int Get(long fileId) { return fileIdMap.GetValueOrDefault(fileId, -1); } internal int Add(long fileId) { int idx = fileIds.Count; fileIdMap.Add(fileId, idx); fileIds.Add(fileId); return idx; } internal SubAssetDetail GetSubDetail(long fileId) { return subDetails.Find(item=>item.fileId == fileId); } public void LoadAllSubAssetsIfNeeded() { if (subDetails != null && subDetails.Count > 0) return; if (fileIds.Count <= 1) return; LoadAllSubAssets(); } private void LoadAllSubAssets() { subDetails.Clear(); if (string.IsNullOrEmpty(guid)) { AssetFinderLOG.LogWarning("Invalid asset GUID."); return; } // Convert GUID to Asset Path string assetPath = AssetDatabase.GUIDToAssetPath(guid); if (string.IsNullOrEmpty(assetPath)) { AssetFinderLOG.LogWarning($"No sub asset found for GUID: {guid}"); return; } UnityObject[] subAssets = AssetDatabase.LoadAllAssetRepresentationsAtPath(assetPath); foreach (UnityObject subAsset in subAssets) { if (AssetDatabase.TryGetGUIDAndLocalFileIdentifier(subAsset, out _, out long localFileID)) { subDetails.Add(new SubAssetDetail(localFileID, subAsset)); } } AssetFinderCacheAsset.MarkAsDirty(); } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/Core/AssetFinderAssetFile.cs.meta ================================================ fileFormatVersion: 2 guid: 1ad1ec70aa912124da3b61e7ef7fb0d9 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/Core/AssetFinderCacheAsset.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using UnityEditor; using UnityEngine; using UnityEngine.Serialization; namespace VirtueSky.AssetFinder.Editor { [CreateAssetMenu] internal class AssetFinderCacheAsset : ScriptableObject { // static APIs private static AssetFinderCacheAsset _api; public static bool isReady => _api != null && _api.db.isReady; internal static void MarkAsDirty() { if (_api == null) return; EditorUtility.SetDirty(_api); } public static AssetFinderAssetFile GetFile(string guid) => _api.db.GetAssetByGUID(guid); public static List CollectUsage(string guid, List result = null) { if (result == null) result = new List(); if (!isReady) { AssetFinderLOG.Log($"CacheAsset is not ready!"); return result; } AssetFinderAssetFile assetFile = GetFile(guid); if (assetFile == null) { Debug.Log($"Asset not found in cache: {guid} : {AssetDatabase.GUIDToAssetPath(guid)}"); return result; } result.AddRange(assetFile.usage); return result; } public static List CollectUsedBy(string guid, long fileId = -1, List result = null) // -1 = all { if (result == null) result = new List(); if (!isReady) { AssetFinderLOG.Log($"CacheAsset is not ready!"); return result; } AssetFinderAssetFile assetFile = _api.db.GetAssetByGUID(guid); if (assetFile == null) { Debug.Log($"Asset not found in cache: {guid} : {AssetDatabase.GUIDToAssetPath(guid)}"); return result; } int subAssetIndex = fileId < 0 ? -1 : assetFile.Get(fileId); // Debug.Log($"CollectUsedBy: {guid}:{fileId} ({subAssetIndex} --> {AssetDatabase.GUIDToAssetPath(guid)} | Count = {assetFile.usedBy.Count}"); if (fileId <= 0 || subAssetIndex <= 0) { result.AddRange(assetFile.usedBy); } else { result.AddRange(assetFile.usedBy.Where(a=> a.toId.SubAssetIndex == subAssetIndex)); } return result; } public static (string guid, long fileId) GetGuidAndFileId(AssetFinderID fr2ID) { if (!isReady) return (null, -1); AssetFinderAssetFile assetFile = _api.db.GetAsset(fr2ID); if (assetFile == null) { AssetFinderLOG.Log($"Asset not found in cache: {fr2ID}"); return (null, -1); } return (assetFile.guid, assetFile.fileIds[fr2ID.SubAssetIndex]); } // Serializable [FormerlySerializedAs("sampleAsset")] [SerializeField] private AssetFinderIDRef sampleID = new AssetFinderIDRef(); [SerializeField] internal AssetFinderAssetDB db = new AssetFinderAssetDB(); [SerializeField] internal List dirtyAssets = new List(); internal static void Init(AssetFinderCacheAsset cache) { _api = cache; _api.db.isReady = false; if (_api.dirtyAssets.Count > 0) { // Do check for changes } _api.db.BuildCache(); } // Scan [ContextMenu("Scan")] internal void Scan() { db.isReady = false; db.Scan(true); EditorUtility.SetDirty(this); } [ContextMenu("BuildCache")] internal void BuildCache() { db.isReady = false; db.BuildCache(); EditorUtility.SetDirty(this); } [ContextMenu("Start Debug")] internal void StartDebug() { AssetFinderUSelection.StartDebugReference(); } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/Core/AssetFinderCacheAsset.cs.meta ================================================ fileFormatVersion: 2 guid: 73b9f1e1c240309488b132c85916b957 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/Core/AssetFinderID.cs ================================================ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using UnityEngine; namespace VirtueSky.AssetFinder.Editor { [StructLayout(LayoutKind.Sequential)] [Serializable] public struct AssetFinderID: IEquatable { private const int SCENE_FLAG_BIT = 31; private const int SUB_INDEX_SHIFT = 21; private const uint SUB_INDEX_MASK = 0x3FFu << SUB_INDEX_SHIFT; private const uint MAIN_INDEX_MASK = 0x1FFFFFu; [SerializeField] private int value; private uint uValue { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => unchecked((uint)value); [MethodImpl(MethodImplOptions.AggressiveInlining)] set => this.value = unchecked((int)value); } private AssetFinderID(int pValue) { value = pValue; } public AssetFinderID(int mainIndex, int subIndex, bool isSceneObject) { if (mainIndex < 0 || mainIndex >= (1 << 21)) { throw new ArgumentOutOfRangeException(nameof(mainIndex)); } if (subIndex < 0 || subIndex >= (1 << 10)) { throw new ArgumentOutOfRangeException(nameof(subIndex)); } uint u = ( (uint)(isSceneObject ? 1 : 0) << SCENE_FLAG_BIT) | ((uint)subIndex << SUB_INDEX_SHIFT) | ((uint)mainIndex & MAIN_INDEX_MASK); value = unchecked((int)u); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public AssetFinderID WithoutSubAssetIndex() => WithSubAssetIndex(0); [MethodImpl(MethodImplOptions.AggressiveInlining)] public AssetFinderID WithSubAssetIndex(int subIndex) { return new AssetFinderID(MainIndex, subIndex, IsSceneObject); } public bool IsSceneObject { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => (uValue & (1u << SCENE_FLAG_BIT)) != 0; } private int MainIndex { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => (int)(uValue & MAIN_INDEX_MASK); } private int SubIndex { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => (int)((uValue & SUB_INDEX_MASK) >> SUB_INDEX_SHIFT); } public int AssetIndex { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => MainIndex; } public int SubAssetIndex { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => SubIndex; } public int GameObjectIndex { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => MainIndex; } public int ComponentIndex { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => SubIndex; } public static implicit operator int(AssetFinderID id) => id.value; public static implicit operator AssetFinderID(int value) => new AssetFinderID(value); public override int GetHashCode() => value; public bool Equals(AssetFinderID other) => value == other.value; public override bool Equals(object obj) => obj is AssetFinderID other && Equals(other); public override string ToString() => IsSceneObject ? $"SceneObject - GameObjectIndex: {GameObjectIndex}, ComponentIndex: {ComponentIndex}" : $"Asset - AssetIndex: {AssetIndex}, SubAssetIndex: {SubAssetIndex}"; // private sealed class Comparer : IEqualityComparer // { // public static readonly Comparer Instance = new Comparer(); // public bool Equals(AssetFinderID x, AssetFinderID y) => x.serializedValue == y.serializedValue; // public int GetHashCode(AssetFinderID obj) => obj.serializedValue; // } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/Core/AssetFinderID.cs.meta ================================================ fileFormatVersion: 2 guid: 2ae340b075e4caf4f8acd2068ca8f27f MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/Core/AssetFinderIDRef.cs ================================================ using System; using UnityEngine; namespace VirtueSky.AssetFinder.Editor { [Serializable] internal class AssetFinderIDRef { [SerializeField] internal AssetFinderID fromId; [SerializeField] internal AssetFinderID toId; // public string type; // The class that reference this asset // public string path; // The property path that the class used to reference to asset // public bool isWeak; // Weak: Addressable / Atlas public override string ToString() { return $"{fromId.ToString()} -> {toId.ToString()}"; } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/Core/AssetFinderIDRef.cs.meta ================================================ fileFormatVersion: 2 guid: 9729cd2c8a35f2647927a913eba11dc6 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/Core/AssetFinderSceneObject.cs ================================================ namespace VirtueSky.AssetFinder.Editor { public class AssetFinderSceneObject { } } ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/Core/AssetFinderSceneObject.cs.meta ================================================ fileFormatVersion: 2 guid: 445ef92693ec9b144956feabd217ac09 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/Core/SubAssetDetail.cs ================================================ using System; using System.Collections.Generic; using UnityEditor; using UnityEngine; using UnityEngine.Audio; using UnityEngine.Video; using Object = UnityEngine.Object; namespace VirtueSky.AssetFinder.Editor { internal enum SubAssetType { Unknown, Sprite, // Part of a multi-sprite texture or sprite atlas Mesh, // Extracted from FBX, OBJ, or Blender files GameObject, // Child of prefab Material, // Can be embedded inside FBX models ScriptableObject, // Nested ScriptableObjects AnimationClip, // From FBX models or Animation files Avatar, // Humanoid Avatar inside an FBX model AudioMixerSnapshot, // Part of an Audio Mixer LightingDataAsset, // Generated lighting data BlendShape, // Internal morph target data from FBX PhysicsMaterial2D, // Sometimes stored inside assets ShaderVariantCollection, // Shader variant sub-assets TerrainLayer, // Used in Terrain systems Texture2DArray, // Array of textures stored inside a single asset Texture3D, // 3D texture data (e.g., volumetric effects) Cubemap, // Used in reflection probes VideoClip, // If part of a larger asset SpineAnimation, // Sub-asset in Spine skeleton data SpineSkeletonData, // Spine skeleton metadata } [Serializable] internal class SubAssetDetail { public long fileId; public string name; public SubAssetType type; public SubAssetDetail(long fileId, Object subAsset) { this.fileId = fileId; name = subAsset.name; type = GetSubAssetType(subAsset); } // Direct Type Mapping (UnityEngine types) private static readonly Dictionary TypeToSubAssetType = new Dictionary { { typeof(Sprite), SubAssetType.Sprite }, { typeof(Mesh), SubAssetType.Mesh }, { typeof(GameObject), SubAssetType.GameObject }, { typeof(AnimationClip), SubAssetType.AnimationClip }, { typeof(Avatar), SubAssetType.Avatar }, { typeof(Material), SubAssetType.Material }, { typeof(AudioMixerSnapshot), SubAssetType.AudioMixerSnapshot }, { typeof(LightingDataAsset), SubAssetType.LightingDataAsset }, { typeof(PhysicsMaterial2D), SubAssetType.PhysicsMaterial2D }, { typeof(ShaderVariantCollection), SubAssetType.ShaderVariantCollection }, { typeof(TerrainLayer), SubAssetType.TerrainLayer }, { typeof(Texture2DArray), SubAssetType.Texture2DArray }, { typeof(Texture3D), SubAssetType.Texture3D }, { typeof(Cubemap), SubAssetType.Cubemap }, { typeof(VideoClip), SubAssetType.VideoClip }, }; // String-based lookup for non-UnityEngine types (Spine, BlendShape, etc.) private static readonly Dictionary TypeNameToSubAssetType = new Dictionary { { "BlendShape", SubAssetType.BlendShape }, // Internal Unity representation { "SpineAnimation", SubAssetType.SpineAnimation }, // Spine-specific { "SpineSkeletonData", SubAssetType.SpineSkeletonData } }; /// /// Gets the SubAssetType from an object instance. /// public static SubAssetType GetSubAssetType(Object subAsset) { if (subAsset == null) return SubAssetType.Unknown; Type assetType = subAsset.GetType(); // 1. Check UnityEngine types directly if (TypeToSubAssetType.TryGetValue(assetType, out SubAssetType mappedType)) { return mappedType; } // 2. Check if it's a ScriptableObject (catch all ScriptableObjects) if (typeof(ScriptableObject).IsAssignableFrom(assetType)) { return SubAssetType.ScriptableObject; } // 3. Check by type name (for custom asset types like Spine) return TypeNameToSubAssetType.TryGetValue(assetType.Name, out mappedType) ? mappedType : SubAssetType.Unknown; } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/Core/SubAssetDetail.cs.meta ================================================ fileFormatVersion: 2 guid: b50e1e50ed9048598749146f243273c0 timeCreated: 1738924564 ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/Core.meta ================================================ fileFormatVersion: 2 guid: 79e0b652bba84906a634b7dcf189ea7d timeCreated: 1730992920 ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/Drawer/AssetFinderAssetFileDrawer.cs ================================================ using System.Collections.Generic; using UnityEditor; using UnityEngine; namespace VirtueSky.AssetFinder.Editor { [CustomPropertyDrawer(typeof(AssetFinderAssetFile))] public class AssetFinderAssetFileDrawer : PropertyDrawer { public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { EditorGUI.BeginProperty(position, label, property); // Get serialized properties var fr2IdProp = property.FindPropertyRelative("fr2Id"); var guidProp = property.FindPropertyRelative("guid"); var fileIdsProp = property.FindPropertyRelative("fileIds"); // Load the asset using the GUID string assetPath = AssetDatabase.GUIDToAssetPath(guidProp.stringValue); // Object asset = AssetDatabase.LoadAssetAtPath(assetPath); // Set fixed widths for AssetFinderID and GUID fields float fr2IdWidth = 70f; float guidWidth = 280f; float spacing = 5f; // Draw Asset Path as clickable label at the top Rect assetPathRect = new Rect(position.x, position.y, position.width, EditorGUIUtility.singleLineHeight); AssetFinderAssetGUI.DrawAsset(assetPathRect, guidProp.stringValue); // Calculate Rects for AssetFinderID and GUID on the same line below the asset path Rect fr2IdRect = new Rect(position.x, assetPathRect.yMax + EditorGUIUtility.standardVerticalSpacing, fr2IdWidth, EditorGUIUtility.singleLineHeight); Rect guidRect = new Rect(fr2IdRect.xMax + spacing, fr2IdRect.y, guidWidth, EditorGUIUtility.singleLineHeight); // Draw GUID button var fr2Id = (AssetFinderID)fr2IdProp.FindPropertyRelative("value").intValue; AssetFinderAssetGUI.DrawId(fr2IdRect, fr2Id); // Draw GUID button AssetFinderAssetGUI.DrawGuid(guidRect, guidProp.stringValue); EditorGUI.indentLevel--; EditorGUI.EndProperty(); } public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { // Calculate height based on the contents var fileIdsProp = property.FindPropertyRelative("fileIds"); float lineHeight = EditorGUIUtility.singleLineHeight; float spacing = EditorGUIUtility.standardVerticalSpacing; // Estimate the number of lines required for the fileId buttons float totalWidth = EditorGUIUtility.currentViewWidth; float currentLineWidth = 0; int lineCount = 1; // Start with one line for (int i = 0; i < fileIdsProp.arraySize; i++) { string fileIdText = fileIdsProp.GetArrayElementAtIndex(i).longValue.ToString(); float buttonWidth = EditorStyles.label.CalcSize(new GUIContent(fileIdText)).x + 8f; if (currentLineWidth + buttonWidth > totalWidth) { lineCount++; currentLineWidth = buttonWidth; } else { currentLineWidth += buttonWidth + spacing; } } return lineHeight * (4 + lineCount) + spacing * 3 + 8f; } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/Drawer/AssetFinderAssetFileDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: 9d0464c486a72c145a862aaf1ec01dbb MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/Drawer/AssetFinderCacheAssetEditor.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using UnityEditor; using UnityEngine; namespace VirtueSky.AssetFinder.Editor { [CustomEditor(typeof(AssetFinderCacheAsset))] internal class AssetFinderCacheAssetEditor : UnityEditor.Editor { private FileUI fileUI; private AssetFinderAssetFile file; private readonly List fileUsage = new List(); private readonly List usages = new List(); public override void OnInspectorGUI() { base.OnInspectorGUI(); if (file == null) return; Rect rect = EditorGUILayout.GetControlRect(); if (fileUI == null) fileUI = AssetUI.Get(file.guid, true); if (fileUI == null) return; // Invalid FileUI var result = rect.ExtractRight(50f); var lbRect = result.Item1; var r = result.Item2; GUI.Label(lbRect, $"({usages.Count})", EditorStyles.miniLabel); var r1 = rect; fileUI.DrawAsset(ref r1, true, false); rect.xMin += 18f; rect.y += 18f; for (var i = 0; i < usages.Count; i++) { var item = usages[i]; item.Draw(ref rect); } } private void OnEnable() { Selection.selectionChanged -= OnChangeSelection; Selection.selectionChanged += OnChangeSelection; } void OnChangeSelection() { if (!AssetFinderCacheAsset.isReady) return; var obj = Selection.activeObject; if (obj == null) return; if (!EditorUtility.IsPersistent(obj)) { // Unsupported: SceneObject return; } if (!AssetDatabase.TryGetGUIDAndLocalFileIdentifier(obj, out string guid, out long localId)) { return; } file = AssetFinderCacheAsset.GetFile(guid); fileUsage.Clear(); AssetFinderCacheAsset.CollectUsage(guid, fileUsage); usages.Clear(); usages.AddRange(fileUsage .Select(item => AssetFinderCacheAsset.GetGuidAndFileId(item.toId)) .Select(item => { AssetFinderAssetFile asset = AssetFinderCacheAsset.GetFile(item.guid); asset.LoadAllSubAssetsIfNeeded(); return item; }) .GroupBy(item => item.guid) .Select(g => new AssetRefUI( g.Key, AssetDatabase.GUIDToAssetPath(g.Key), g.Select(item => item.fileId).ToList()))); GC.Collect(); Resources.UnloadUnusedAssets(); Repaint(); } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/Drawer/AssetFinderCacheAssetEditor.cs.meta ================================================ fileFormatVersion: 2 guid: 6748e1a1e91d4094286862d7c9aea483 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/Drawer/AssetFinderIDDrawer.cs ================================================ using UnityEngine; using UnityEditor; namespace VirtueSky.AssetFinder.Editor { [CustomPropertyDrawer(typeof(AssetFinderID))] public class AssetFinderIDDrawer : PropertyDrawer { public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { // Get the 'value' field in the serialized property var valueProp = property.FindPropertyRelative("value"); var assetIndex = (valueProp.intValue >> 10) & 0x3FFFFF; var subAssetIndex = valueProp.intValue & 0x3FF; // Set the button content with assetIndex and subAssetIndex, and show value as tooltip GUIContent buttonContent = AssetFinderGUIContent.FromString($"[{assetIndex} : {subAssetIndex}]", $"Value: {valueProp.intValue}"); GUI.Label(position, buttonContent); // EditorGUIUtility.systemCopyBuffer = valueProp.intValue.ToString(); // Debug.Log("Copied Value: " + EditorGUIUtility.systemCopyBuffer); } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/Drawer/AssetFinderIDDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: ccc51a6989160944688a10eb95b36fcd MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/Drawer.meta ================================================ fileFormatVersion: 2 guid: c5ef076df01604f89987b1c1701a11bd folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/GUI/AssetFinderAssetGUI.cs ================================================ using UnityEditor; using UnityEngine; namespace VirtueSky.AssetFinder.Editor { public static class AssetFinderAssetGUI { public class DrawContext { public bool drawPath = false; public bool drawHighlight = true; } // draw context public static DrawContext context = new DrawContext(); public static void DrawAsset(Rect rect, AssetFinderID id) { var assetFR2Id = id.WithoutSubAssetIndex(); var (guid, _) = AssetFinderCacheAsset.GetGuidAndFileId(assetFR2Id); DrawAsset(rect, guid); } public static void DrawId(Rect rect, AssetFinderID fr2Id) { var fr2IdWidth = 70f; int assetIndex = fr2Id.AssetIndex; int subIndex = fr2Id.SubAssetIndex; GUIContent title = AssetFinderGUIContent.FromString($"[{assetIndex}-{subIndex}]", $"Value: {fr2Id}"); if (GUI.Button(GUI2.LeftRect(fr2IdWidth, ref rect), title)) { EditorGUIUtility.systemCopyBuffer = fr2Id.ToString(); UnityEngine.Debug.Log("Copied AssetFinderID Value: " + EditorGUIUtility.systemCopyBuffer); } } public static void DrawGuid(Rect rect, string guid) { var fr2IdWidth = 250f; GUIContent title = AssetFinderGUIContent.FromString(guid, "Click to copy GUID"); if (GUI.Button(GUI2.LeftRect(fr2IdWidth, ref rect), title)) { EditorGUIUtility.systemCopyBuffer = guid; AssetFinderLOG.Log("Copied AssetFinderID Value: " + EditorGUIUtility.systemCopyBuffer); } } public static void DrawAsset(Rect rect, string guid) { var info = AssetFinderAssetInfo.GetOrCreate(guid); if (info.folderContent == null) info.RefreshGUIContent(); float pathW = context.drawPath ? EditorStyles.miniLabel.CalcSize(info.folderContent).x : 8f; float nameW = context.drawPath ? EditorStyles.boldLabel.CalcSize(info.fileNameContent).x : EditorStyles.label.CalcSize(info.fileNameContent).x; float extW = string.IsNullOrEmpty(info.fileExt) ? 0f : EditorStyles.miniLabel.CalcSize(info.fileExtContent).x; Rect iconRect = GUI2.LeftRect(16f, ref rect); if (Event.current.type == EventType.Repaint) { Texture icon = AssetDatabase.GetCachedIcon(info.assetPath); if (icon != null) GUI.DrawTexture(iconRect, icon, ScaleMode.ScaleToFit); } if (context.drawPath) { Color c2 = GUI.color; GUI.color = new Color(c2.r, c2.g, c2.b, c2.a * 0.5f); GUI.Label(GUI2.LeftRect(pathW, ref rect), info.folderContent, EditorStyles.miniLabel); GUI.color = c2; rect.xMin -= 2f; } GUI.Label(GUI2.LeftRect(nameW, ref rect), info.fileNameContent, context.drawPath ? EditorStyles.boldLabel : EditorStyles.label); if (extW > 0) { rect.xMin -= 2f; GUI.Label(GUI2.LeftRect(extW, ref rect), info.fileExtContent, EditorStyles.miniLabel); } } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/GUI/AssetFinderAssetGUI.cs.meta ================================================ fileFormatVersion: 2 guid: ce2370394863b3a4e8defddcd3099ac5 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/GUI/AssetFinderAssetInfo.cs ================================================ using System; using System.Collections.Generic; using UnityEditor; using UnityEngine; namespace VirtueSky.AssetFinder.Editor { public class AssetFinderAssetInfo { [NonSerialized] internal static readonly Dictionary infoMap = new Dictionary(); internal static AssetFinderAssetInfo Get(string guid) => infoMap.GetValueOrDefault(guid); internal static AssetFinderAssetInfo GetOrCreate(string guid) => infoMap.GetValueOrDefault(guid) ?? new AssetFinderAssetInfo(guid); internal static void Clear() => infoMap.Clear(); public string guid; public string assetPath; public string folder; public string fileName; public string fileExt; // GUIContent public GUIContent folderContent; public GUIContent fileNameContent; public GUIContent fileExtContent; private AssetFinderAssetInfo(string guid) { this.guid = guid; assetPath = AssetDatabase.GUIDToAssetPath(guid); folder = System.IO.Path.GetDirectoryName(assetPath) + "/"; fileName = System.IO.Path.GetFileNameWithoutExtension(assetPath); fileExt = System.IO.Path.GetExtension(assetPath); infoMap.Add(guid, this); } public void RefreshGUIContent() { folderContent = AssetFinderGUIContent.From(folder); fileNameContent = AssetFinderGUIContent.From(fileName); fileExtContent = string.IsNullOrEmpty(fileExt) ? GUIContent.none : AssetFinderGUIContent.From(fileExt); } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/GUI/AssetFinderAssetInfo.cs.meta ================================================ fileFormatVersion: 2 guid: 74f0b16f4b79c4b4cabbb09c38ddc794 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/GUI.meta ================================================ fileFormatVersion: 2 guid: 59606708556974356adfa65945cc7c11 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/Parser/AssetFinderParser.BinaryAsset.cs ================================================ using System; using System.Collections.Generic; using System.IO; using UnityEngine; using UnityEditor; using UnityObject = UnityEngine.Object; using AddUsageCB = System.Action; namespace VirtueSky.AssetFinder.Editor { internal static partial class AssetFinderParser // BinaryAsset { private static HashSet BINARY_ASSET = new HashSet() { ".asset", ".spriteatlas", ".unity" }; private static bool Read_VerifyBinaryAsset(string assetPath) { try { foreach (string line in File.ReadLines(assetPath)) { return !line.StartsWith("%YAML", StringComparison.Ordinal); } } catch (Exception e) { LogWarning($"Read_VerifyBinaryAsset error: {assetPath}\n{e}"); } // Should never be here! return false; } private static void ReadContent_BinaryAsset(string filePath, AddUsageCB callback) { string ext = Path.GetExtension(filePath).ToLowerInvariant(); if (!BINARY_ASSET.Contains(ext)) return; var allAssets = AssetDatabase.LoadAllAssetsAtPath(filePath); foreach (UnityObject assetData in allAssets) { LogWarning($"Asset: {assetData} : {assetData.GetType()}"); if (assetData is GameObject go) { Component[] compList = go.GetComponentsInChildren(true); for (var i = 0; i < compList.Length; i++) { LoadSerialized(compList[i], callback); } } else if (assetData is TerrainData terrainData) { Read_TerrainData(terrainData, callback); } else if (assetData is LightingDataAsset lightingDataAsset) { Read_LightMap(lightingDataAsset, callback); } else { LoadSerialized(assetData, callback); } } } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/Parser/AssetFinderParser.BinaryAsset.cs.meta ================================================ fileFormatVersion: 2 guid: 118795563d36de44a8d02c8399654aec MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/Parser/AssetFinderParser.LightMap.cs ================================================ using UnityEditor; using AddUsageCB = System.Action; namespace VirtueSky.AssetFinder.Editor { internal static partial class AssetFinderParser // LightMap { // BWCompatible internal static void LoadLightingData(this AssetFinderAsset asset, LightingDataAsset data) { Read_LightMap(data, (guid, fileId) => asset.AddUseGUID(guid, fileId)); } private static void Read_LightMap(LightingDataAsset asset, AddUsageCB callback) { if (asset == null) return; foreach (var texture in AssetFinderLightmap.Read(asset)) { AddObjectUsage(texture, callback); } } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/Parser/AssetFinderParser.LightMap.cs.meta ================================================ fileFormatVersion: 2 guid: 63fe5cc863d036d43a50260f5365edd7 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/Parser/AssetFinderParser.Model3D.cs ================================================ using System; using System.Collections.Generic; using UnityEditor; using UnityEngine; using UnityObject = UnityEngine.Object; using AddUsageCB = System.Action; namespace VirtueSky.AssetFinder.Editor { internal static partial class AssetFinderParser // Model3D { private static readonly HashSet MODEL_FILES = new HashSet() { ".fbx", ".obj", ".3ds", ".dxf", ".max", ".c4d", ".blend", ".lwo", ".lws", ".ma", ".mb", ".jas", ".skp", ".dae", ".3dm", ".stl", ".ply", ".dxf", ".lwo", ".lws" }; private static void Read_Model3D(GameObject go, AddUsageCB callback) { Component[] compList = go.GetComponentsInChildren(); for (var i = 0; i < compList.Length; i++) { LoadSerialized(compList[i], callback); } } private static void LoadSerialized(UnityObject target, AddUsageCB callback) { SerializedProperty[] props = AssetFinderUnity.xGetSerializedProperties(target, true); for (var i = 0; i < props.Length; i++) { if (props[i].propertyType != SerializedPropertyType.ObjectReference) continue; UnityObject refObj = props[i].objectReferenceValue; AddObjectUsage(refObj, callback); } } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/Parser/AssetFinderParser.Model3D.cs.meta ================================================ fileFormatVersion: 2 guid: d1d35288c86839146b50b9e6c2963c62 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/Parser/AssetFinderParser.Shader.cs ================================================ using System; using System.Text.RegularExpressions; namespace VirtueSky.AssetFinder.Editor { internal static partial class AssetFinderParser // Shader { private static void ReadContent_Shader(string filePath, Action callback) { Log($"[FR2] Reading shader file: {filePath}"); Read(filePath, ParseLine_Shader, callback, false); // Don't use double-check for shader files } private static (string guid, long fileId) ParseLine_Shader(string line) { #if AssetFinderDEV if (line.TrimStart().StartsWith("#include")) { Log($"[FR2] Processing include line: {line.Trim()}"); } #endif // Pattern 1: #include directives with quotes // Example: #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl" if (line.TrimStart().StartsWith("#include")) { string includePath = Find(line, "#include \"", "\""); Log($"[FR2] Found quoted include path: '{includePath}'"); if (!string.IsNullOrEmpty(includePath)) { string resolvedPath = ResolveShaderIncludePath(includePath); Log($"[FR2] Resolved path: '{resolvedPath}'"); if (!string.IsNullOrEmpty(resolvedPath)) { string guid = UnityEditor.AssetDatabase.AssetPathToGUID(resolvedPath); Log($"[FR2] Path to GUID: '{resolvedPath}' -> '{guid}'"); if (!string.IsNullOrEmpty(guid)) { Log($"[FR2] SUCCESS - Shader Include: {includePath} -> {resolvedPath} -> {guid}"); return (guid, -1); } } } } // Pattern 2: #include directives with angle brackets // Example: #include if (line.TrimStart().StartsWith("#include")) { string includePath = Find(line, "#include <", ">"); if (!string.IsNullOrEmpty(includePath)) { string resolvedPath = ResolveShaderIncludePath(includePath); if (!string.IsNullOrEmpty(resolvedPath)) { string guid = UnityEditor.AssetDatabase.AssetPathToGUID(resolvedPath); if (!string.IsNullOrEmpty(guid)) { Log($"[FR2] Shader Include: {includePath} -> {resolvedPath} -> {guid}"); return (guid, -1); } } } } return (null, -1); } private static string ResolveShaderIncludePath(string includePath) { if (string.IsNullOrEmpty(includePath)) return null; Log($"[FR2] Resolving shader include path: '{includePath}'"); // Pattern 1: Packages/ references // Example: "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl" if (includePath.StartsWith("Packages/")) { // Check if the path exists directly if (System.IO.File.Exists(includePath)) { Log($"[FR2] Found direct package path: {includePath}"); return includePath; } } // Pattern 2: Relative paths from project // Example: "Assets/Shaders/Common.hlsl" if (includePath.StartsWith("Assets/")) { if (System.IO.File.Exists(includePath)) { return includePath; } } // Pattern 3: Search in common Unity shader include directories string[] searchDirectories = { "Assets/", "Assets/Shaders/", "Assets/Scripts/Shaders/", "Packages/com.unity.render-pipelines.core/ShaderLibrary/", "Packages/com.unity.render-pipelines.universal/ShaderLibrary/", "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/", "Packages/com.unity.shadergraph/ShaderGraphLibrary/" }; foreach (string searchDir in searchDirectories) { string fullPath = searchDir + includePath; if (System.IO.File.Exists(fullPath)) { return fullPath; } // Also try without directory structure (flat search) string fileName = System.IO.Path.GetFileName(includePath); string flatPath = searchDir + fileName; if (System.IO.File.Exists(flatPath)) { return flatPath; } } // Pattern 4: Search using Unity's AssetDatabase for filename matches string targetFileName = System.IO.Path.GetFileNameWithoutExtension(includePath); string targetExtension = System.IO.Path.GetExtension(includePath); if (string.IsNullOrEmpty(targetExtension)) { // Try common shader extensions if no extension provided string[] extensions = { ".hlsl", ".cginc", ".shader", ".glsl" }; foreach (string ext in extensions) { string[] matchingGuids = UnityEditor.AssetDatabase.FindAssets($"{targetFileName} t:DefaultAsset"); foreach (string guid in matchingGuids) { string assetPath = UnityEditor.AssetDatabase.GUIDToAssetPath(guid); if (assetPath.EndsWith(ext) && System.IO.Path.GetFileNameWithoutExtension(assetPath) == targetFileName) { return assetPath; } } } } else { // Search for exact filename match string[] matchingGuids = UnityEditor.AssetDatabase.FindAssets($"{targetFileName} t:DefaultAsset"); foreach (string guid in matchingGuids) { string assetPath = UnityEditor.AssetDatabase.GUIDToAssetPath(guid); if (System.IO.Path.GetFileName(assetPath).Equals(System.IO.Path.GetFileName(includePath), StringComparison.OrdinalIgnoreCase)) { return assetPath; } } } return null; } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/Parser/AssetFinderParser.Shader.cs.meta ================================================ fileFormatVersion: 2 guid: 933793502ca2eb2499dc3b6bc25a4dc4 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/Parser/AssetFinderParser.ShaderGraph.cs ================================================ using System; using System.Collections.Generic; namespace VirtueSky.AssetFinder.Editor { internal static partial class AssetFinderParser // ShaderGraph { private static readonly Dictionary> SHADER_GRAPH_FILES = new Dictionary>() { { ".shadergraph", ParseLine_Json }, { ".shadersubgraph", ParseLine_Json }, }; private static void ReadContent_ShaderGraph(string ext, string assetPath, Action callback) { Func lineParser = SHADER_GRAPH_FILES[ext]; Read(assetPath, lineParser, callback); } private static (string guid, long fileId) ParseLine_Json(string line) { string guid = Find(line, "\\\"guid\\\":\\\"", "\\\","); if (string.IsNullOrEmpty(guid)) return (null, -1); string fileIdStr = Find(line, "\"fileID\\\":", ","); if (string.IsNullOrEmpty(fileIdStr)) return (null, -1); if (!long.TryParse(fileIdStr, out long fileId)) fileId = -1; return (guid, fileId); } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/Parser/AssetFinderParser.ShaderGraph.cs.meta ================================================ fileFormatVersion: 2 guid: a30b788b96d832b41bcada6c0eaffa99 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/Parser/AssetFinderParser.Terrain.cs ================================================ using System; using UnityEngine; using UnityEditor; using AddUsageCB = System.Action; namespace VirtueSky.AssetFinder.Editor { internal static partial class AssetFinderParser // Terrain { // BWCompatible internal static void LoadTerrainData(this AssetFinderAsset asset, TerrainData data) { Read_TerrainData(data, (string guid, long fileId) => asset.AddUseGUID(guid, fileId)); } private static void Read_TerrainData(TerrainData terrain, AddUsageCB callback) { #if UNITY_2018_3_OR_NEWER TerrainLayer[] layers = terrain.terrainLayers; for (var i = 0; i < layers.Length; i++) { AddObjectUsage(layers[i], callback); } #endif DetailPrototype[] details = terrain.detailPrototypes; for (var i = 0; i < details.Length; i++) { AddObjectUsage(details[i].prototypeTexture, callback); } TreePrototype[] trees = terrain.treePrototypes; for (var i = 0; i < trees.Length; i++) { AddObjectUsage(trees[i].prefab, callback); } AssetFinderTerrain.TerrainTextureData[] texDatas = AssetFinderTerrain.GetTerrainTextureDatas(terrain); for (var i = 0; i < texDatas.Length; i++) { AssetFinderTerrain.TerrainTextureData texs = texDatas[i]; for (var k = 0; k < texs.textures.Length; k++) { Texture2D tex = texs.textures[k]; if (tex == null) continue; AssetDatabase.TryGetGUIDAndLocalFileIdentifier(tex, out string refGUID, out long fileId); callback(refGUID, fileId); } } } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/Parser/AssetFinderParser.Terrain.cs.meta ================================================ fileFormatVersion: 2 guid: c29120f806f185647b4021d77b976629 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/Parser/AssetFinderParser.UIToolkit.cs ================================================ using System; using System.Collections.Generic; using System.IO; using UnityEditor; using UnityEngine; namespace VirtueSky.AssetFinder.Editor { internal static partial class AssetFinderParser // UIToolkit { private static readonly Dictionary> UI_TOOLKIT_FILES = new Dictionary>() { {".tss", ParseLine_Tss}, {".uxml", ParseLine_Uxml_Uss}, {".uss", ParseLine_Uxml_Uss} }; private static void ReadContent_UIToolkit(string ext, string assetPath, Action callback) { Func lineParser = UI_TOOLKIT_FILES[ext]; Read(assetPath, lineParser, callback); } private static (string guid, long fileId) ParseLine_Uxml_Uss(string line) { // Check for traditional GUID references first var result = FindRef(line, "guid=", "fileID=", "&"); if (result.guid != null) return result; // Handle UXML Style src references with project://database/ URIs if (line.Contains("USS: {srcPath} -> {resolvedPath} -> {guid}"); return (guid, -1); } } else { AssetFinderLOG.LogWarning($"[FR2] Failed to resolve UXML Style src: {srcPath}"); } } } // Handle resource() references for USS files if (line.Contains("resource(")) { string resourcePath = Find(line, "resource(\"", "\")"); if (string.IsNullOrEmpty(resourcePath)) { resourcePath = Find(line, "resource('", "')"); } if (!string.IsNullOrEmpty(resourcePath)) { // Unity resource paths can be relative to various locations string guid = ResolveResourcePath(resourcePath); if (!string.IsNullOrEmpty(guid)) { return (guid, -1); } } } // Handle @import ""; references for USS files : @import "Base.uss"; if (line.Contains("@import")) { string importPath = Find(line, "@import \"", "\";"); if (string.IsNullOrEmpty(importPath)) { importPath = Find(line, "@import '", "';"); } if (!string.IsNullOrEmpty(importPath)) { // Unity resource paths can be relative to various locations string resolvedPath = ResolveProjectDatabasePath(importPath); if (!string.IsNullOrEmpty(resolvedPath)) { string guid = AssetDatabase.AssetPathToGUID(resolvedPath); if (!string.IsNullOrEmpty(guid)) { // AssetFinderLOG.Log($"[FR2] USS->USS: {importPath} -> {resolvedPath} -> {guid}"); return (guid, -1); } } else { AssetFinderLOG.LogWarning($"[FR2] Failed to resolve USS import: {importPath}"); } } } return (null, -1); } private static string ResolveProjectDatabasePath(string path) { // Handle project://database/ URIs if (path.StartsWith("project://database/")) { // Remove the project://database/ prefix to get the actual asset path string assetPath = path.Substring("project://database/".Length); // Check if this path exists in the project if (System.IO.File.Exists(assetPath)) { return assetPath; } } // full path if (System.IO.File.Exists(path)) return path; // relative path var folder = parsingFilePath.Substring(0, parsingFilePath.LastIndexOf('/')); var fullRelativePath = Path.Combine(folder, path); if (System.IO.File.Exists(fullRelativePath)) { return fullRelativePath; } return null; } private static string ResolveResourcePath(string resourcePath) { // Common Unity resource locations to search string[] searchPaths = { $"Assets/Editor Default Resources/{resourcePath}", $"Assets/Resources/{resourcePath}", $"Assets/{resourcePath}", resourcePath }; foreach (string searchPath in searchPaths) { if (System.IO.File.Exists(searchPath)) { return AssetDatabase.AssetPathToGUID(searchPath); } } // Check in all package locations string[] packageGuids = AssetDatabase.FindAssets($"t:DefaultAsset {System.IO.Path.GetFileNameWithoutExtension(resourcePath)}"); foreach (string guid in packageGuids) { string path = AssetDatabase.GUIDToAssetPath(guid); if (path.EndsWith(resourcePath)) { return guid; } } return null; } private static (string guid, long fileId) ParseLine_Tss(string line) { string assetPath = Find(line, "@importurl(\"/", "\")"); return string.IsNullOrEmpty(assetPath) ? (null, -1) : (AssetDatabase.AssetPathToGUID(assetPath), 0); } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/Parser/AssetFinderParser.UIToolkit.cs.meta ================================================ fileFormatVersion: 2 guid: ab428f706dd08db41981186820926948 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/Parser/AssetFinderParser.Yaml.cs ================================================ using System; using System.Collections.Generic; using System.IO; namespace VirtueSky.AssetFinder.Editor { internal static partial class AssetFinderParser // Yaml { private static readonly HashSet YAML_FILES = new HashSet() { ".anim", ".controller", ".mat", ".unity", ".guiskin", ".prefab", ".overridecontroller", ".mask", ".rendertexture", ".cubemap", ".flare", ".playable", ".physicsmaterial", ".fontsettings", ".asset", ".prefs", ".spriteatlas", ".terrainlayer", ".asmdef", ".preset", ".spriteLib", ".texture2darray" }; private static void ReadContent_YAML(string filePath, Action callback) { string ext = Path.GetExtension(filePath).ToLowerInvariant(); bool isBinary = BINARY_ASSET.Contains(ext) && Read_VerifyBinaryAsset(filePath); if (isBinary) { ReadContent_BinaryAsset(filePath, callback); } else { Read(filePath, ParseLine_Yaml, callback); } } private static (string guid, long fileId) ParseLine_Yaml(string line) { // Check for both 'guid:' and 'm_AssetGUID:' patterns (string guid, long fileId) result = FindRef(line, "guid:", "fileID:", ","); if (result.guid != null) return result; result = FindRef(line, "m_AssetGUID:", null, null); return string.IsNullOrEmpty(result.guid) ? FindRef(line, "GUID:", null, null) : result; } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/Parser/AssetFinderParser.Yaml.cs.meta ================================================ fileFormatVersion: 2 guid: fb684659a7b55c84c9de5867ca66c64e MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/Parser/AssetFinderParser.cs ================================================ // #define AssetFinderPARSER_DEBUG using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Text; using UnityEditor; using UnityEngine; using AddUsageCB = System.Action; namespace VirtueSky.AssetFinder.Editor { // Public APIs internal static partial class AssetFinderParser { private static readonly HashSet META_FILES = new HashSet() { ".texture2darray",".png", ".jpg", ".jpeg", ".tga", ".tif", ".tiff", ".psd", ".bmp", ".exr", ".gif", // Support static references ".shader", ".cs", // Custom importers ".shadergraph" }; private static readonly HashSet SHADER_FILES = new HashSet() { ".shader", ".hlsl", ".cginc", ".glsl" }; public static bool IsReadable(string assetPath) { string ext = Path.GetExtension(assetPath).ToLowerInvariant(); return IsReadableExtension(ext); } public static bool IsReadableExtension(string ext) { return YAML_FILES.Contains(ext) || UI_TOOLKIT_FILES.ContainsKey(ext) || SHADER_GRAPH_FILES.ContainsKey(ext) || META_FILES.Contains(ext) || SHADER_FILES.Contains(ext); } [Conditional("AssetFinderPARSER_DEBUG")] public static void LogWarning(string message, UnityEngine.Object target = null) => UnityEngine.Debug.LogWarning(message, target); [Conditional("AssetFinderPARSER_DEBUG")] public static void Log(string message, UnityEngine.Object target = null) => UnityEngine.Debug.Log(message, target); public static void ReadContent(string filePath, AddUsageCB callback) { string ext = Path.GetExtension(filePath).ToLowerInvariant(); bool readMeta = META_FILES.Contains(ext); if (readMeta) // Also need to read .meta file { ReadContent_YAML(filePath + ".meta", callback); } if (YAML_FILES.Contains(ext)) { ReadContent_YAML(filePath, callback); return; } if (SHADER_GRAPH_FILES.ContainsKey(ext)) { ReadContent_ShaderGraph(ext, filePath, callback); return; } if (UI_TOOLKIT_FILES.ContainsKey(ext)) { ReadContent_UIToolkit(ext, filePath, callback); return; } if (SHADER_FILES.Contains(ext)) { // TODO: VALIDATE // ReadContent_Shader(filePath, callback); return; } if (!readMeta) LogWarning("Unknown file type: " + filePath); } } internal static partial class AssetFinderParser { private static string parsingFilePath; private static void AddObjectUsage(UnityEngine.Object refObj, AddUsageCB callback) { if (refObj == null) return; if (AssetDatabase.TryGetGUIDAndLocalFileIdentifier(refObj, out string refGUID, out long fileId)) { callback(refGUID, fileId); } } private static void Read(string filePath, Func lineHandler, Action add, bool doubleCheck = true) { if (!File.Exists(filePath)) return; parsingFilePath = filePath; // Use a buffer to reduce file I/O overhead using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read, 4096)) using (var sr = new StreamReader(fs, Encoding.UTF8, false, 4096)) { string line; while ((line = sr.ReadLine()) != null) { if (string.IsNullOrEmpty(line)) continue; var (guid, fileId) = lineHandler(line); if (!string.IsNullOrEmpty(guid)) { add(guid, fileId); // Debug.Log($"Found: <{guid}:{fileId}>"); continue; } if (!doubleCheck) continue; guid = ExtractGuid(line); if (!string.IsNullOrEmpty(guid)) { LogWarning($"Missed GUID <{guid}>?\n{filePath}\n{line}\n"); add(guid, 0); } } } } private static string ExtractGuid(string line) { const int GuidLength = 32; var validCharCount = 0; for (var i = 0; i < line.Length; i++) { // Check if the character is a valid hex character (0-9, a-f, A-F) if (IsHexChar(line[i])) { validCharCount++; if (validCharCount == GuidLength) { // Return substring from the start of the valid sequence return line.Substring(i - GuidLength + 1, GuidLength); } } else { // Reset count if a non-hex character interrupts the sequence validCharCount = 0; } } return null; // No valid GUID found } // Helper method to check if a character is a hex character private static bool IsHexChar(char c) { return ((c >= '0') && (c <= '9')) || ((c >= 'a') && (c <= 'f')) || ((c >= 'A') && (c <= 'F')); } private static (string guid, long fileId) FindRef(string source, string guidPattern, string fileIdPattern, string separatorPattern) { string guid = Find(source, guidPattern, separatorPattern); if (string.IsNullOrEmpty(guid)) return (null, -1); if (string.IsNullOrEmpty(fileIdPattern)) return (guid, -1); string fileIdStr = Find(source, fileIdPattern, separatorPattern); if (string.IsNullOrEmpty(fileIdStr)) return (null, -1); if (!long.TryParse(fileIdStr, out long fileId)) fileId = -1; // Debug.Log($"Found: {guid}/{fileId}\t\t {source}"); return (guid, fileId); } private static string Find(string source, string str_begin, string str_end) { int st = source.IndexOf(str_begin, StringComparison.Ordinal); if (st == -1) return null; st += str_begin.Length; while (st < source.Length && char.IsWhiteSpace(source[st])) { st++; } if (string.IsNullOrEmpty(str_end)) // no end: determine by length { // Check if we have enough characters left for a valid GUID (32 characters) int remainingLength = source.Length - st; if (remainingLength < 32) return null; // Not enough characters for a valid GUID return source.Substring(st, 32); } int ed = source.IndexOf(str_end, st, StringComparison.Ordinal); if (ed == -1) return null; while (ed > st && char.IsWhiteSpace(source[ed - 1])) { ed--; } return source.Substring(st, ed - st); } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/Parser/AssetFinderParser.cs.meta ================================================ fileFormatVersion: 2 guid: 66a97d939b2702e438522fd09b5d5a1f MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/Parser.meta ================================================ fileFormatVersion: 2 guid: 2aa94c45360ab429f954c2adc286a124 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/UI/AssetRefUI.cs ================================================ using System; using System.Collections.Generic; using UnityEditor; using UnityEngine; namespace VirtueSky.AssetFinder.Editor { internal class AssetRefUI : FileUI { private static Dictionary SubAssetIcons; private Texture2D GetIcon(SubAssetType subType) { if (subType == SubAssetType.Unknown) return null; if (SubAssetIcons == null) CacheIcon(); return SubAssetIcons.GetValueOrDefault(subType); } /// /// Caches icons for different SubAssetTypes using Unity’s internal icon system. /// public static void CacheIcon() { SubAssetIcons = new Dictionary { [SubAssetType.Sprite] = LoadIcon("d_Texture Icon"), [SubAssetType.Mesh] = LoadIcon("d_Mesh Icon"), [SubAssetType.AnimationClip] = LoadIcon("d_AnimationClip Icon"), [SubAssetType.Avatar] = LoadIcon("d_Avatar Icon"), [SubAssetType.Material] = LoadIcon("d_Material Icon"), [SubAssetType.AudioMixerSnapshot] = LoadIcon("d_AudioMixerController Icon"), [SubAssetType.LightingDataAsset] = LoadIcon("LightingDataAsset Icon", "LightProbeGroup Icon"), [SubAssetType.ScriptableObject] = LoadIcon("d_ScriptableObject Icon"), [SubAssetType.ShaderVariantCollection] = LoadIcon("d_Shader Icon"), [SubAssetType.Texture2DArray] = LoadIcon("d_Texture Icon"), [SubAssetType.Cubemap] = LoadIcon("d_Cubemap Icon", "PreTexCube"), [SubAssetType.SpineAnimation] = LoadIcon("d_Animation Icon"), [SubAssetType.SpineSkeletonData] = LoadIcon("d_Animation Icon"), [SubAssetType.PhysicsMaterial2D] = LoadIcon("d_PhysicMaterial Icon", "d_Texture Icon") }; } /// /// Loads a Unity Editor icon with optional fallback support. /// private static Texture2D LoadIcon(string iconName, string fallbackIcon = null) { Texture2D icon = EditorGUIUtility.IconContent(iconName).image as Texture2D; if (icon == null && !string.IsNullOrEmpty(fallbackIcon)) { icon = EditorGUIUtility.IconContent(fallbackIcon).image as Texture2D; } return icon ?? EditorGUIUtility.IconContent("DefaultAsset Icon").image as Texture2D; } private readonly List details = new List(); public AssetRefUI(string guid, string path, List localIds):base(guid, path) { var file = AssetFinderCacheAsset.GetFile(guid); for (var i = 0; i < localIds.Count; i++) { long localId = localIds[i]; var detail = file.GetSubDetail(localId); details.Add(detail); } } public void DrawSubDetails(Rect rect, SubAssetDetail detail) { if (detail == null) return; rect.xMin += 16f; rect.height = AssetFinderTheme.Current.TreeItemHeight; Rect iconRect = new Rect(rect.x, rect.y, 16f, 16f); var icon = GetIcon(detail.type); if (icon != null) { GUI.DrawTexture(iconRect, icon, ScaleMode.ScaleToFit); } // Draw label underneath var labelRect = new Rect(rect.x + 16f, rect.y, rect.width, 16); GUI.Label(labelRect, detail.name); } public void Draw(ref Rect rect) { // Draw main Asset Rect r1 = rect; DrawAsset(ref r1, true, false); rect.y += 18f; // Draw references: should exclude main asset? for (var i = 0; i < details.Count; i++) { var detail = details[i]; if (detail == null) continue; DrawSubDetails(rect, details[i]); rect.y += 18f; } } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/UI/AssetRefUI.cs.meta ================================================ fileFormatVersion: 2 guid: a0104b91001f4474b7ccdb647abfeef2 timeCreated: 1738922219 ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/UI/AssetUI.cs ================================================ using System; using System.Collections.Generic; using System.IO; using UnityEditor; using UnityEngine; namespace VirtueSky.AssetFinder.Editor { public abstract partial class AssetUI { internal static readonly FolderUI NO_PARENT = new FolderUI(string.Empty, string.Empty); // Cache internal static readonly Dictionary cache = new Dictionary(); internal static AssetUI Get(string guid, bool autoNew = false) { AssetUI result = cache.GetValueOrDefault(guid); if (!autoNew || result != null) return result; string path = AssetDatabase.GUIDToAssetPath(guid); if (string.IsNullOrEmpty(path)) return null; bool isFolder = AssetDatabase.IsValidFolder(path); result = isFolder ? (AssetUI)new FolderUI(guid, path) : (AssetUI)new FileUI(guid, path); cache[guid] = result; return result; } internal static T Get(string guid, bool autoNew = false) where T: AssetUI { return Get(guid, autoNew) as T; } // Instance variables public string path; public readonly string guid; [NonSerialized] internal AssetUI _parent; public void RefreshPath() { path = AssetDatabase.GUIDToAssetPath(guid); _parent = null; // also clear cached content nameContent?.Clear(); pathContent?.Clear(); } public AssetUI Parent { get { if (_parent != null) return _parent; int idx = path.LastIndexOf("/", StringComparison.Ordinal); if (idx == -1) return _parent = NO_PARENT; string pPath = path.Substring(0, idx); string pGUID = AssetDatabase.AssetPathToGUID(pPath); _parent = Get(pGUID, true) ?? NO_PARENT; return _parent; } } protected AssetUI(string guid, string path) { this.guid = guid; this.path = path; } } internal class AssetNameContent { internal GUIContent nameContent; internal GUIContent extContent; internal float nameWidth; internal float extWidth; internal bool isValid => nameContent != null; internal bool hasExt => extContent != null; internal void Clear() { nameContent = null; extContent = null; nameWidth = 0; extWidth = 0; } internal void Refresh(string path) { string assetName = Path.GetFileNameWithoutExtension(path); string ext = Path.GetExtension(path); // do not use tooltip (as many files with the same name may shared this content) nameContent = AssetFinderGUIContent.FromString(assetName); nameWidth = EditorStyles.label.CalcSize(nameContent).x; extContent = string.IsNullOrEmpty(ext) ? null : AssetFinderGUIContent.FromString(ext); extWidth = string.IsNullOrEmpty(ext) ? 0 : EditorStyles.label.CalcSize(extContent).x; } } internal class AssetPathContent { internal GUIContent pathContent; internal float pathWidth; internal bool isValid => pathContent != null; internal void Clear() { pathContent = null; pathWidth = 0; } internal void Refresh(string path) { // do not use tooltip (as many files with the same name may shared this content) pathContent = AssetFinderGUIContent.FromString(path); pathWidth = EditorStyles.label.CalcSize(pathContent).x; } } partial class AssetUI // GUID Content { // CONST public const float GUID_WIDTH = 250f; internal GUIContent guidContent; public bool DrawGuid(ref Rect rect) { if (guidContent == null) guidContent = new GUIContent(guid, "Click to copy GUID"); Rect guidRect = GUI2.LeftRect(GUID_WIDTH, ref rect); if (!GUI.Button(guidRect, guidContent)) return false; // Clicked EditorGUIUtility.systemCopyBuffer = guid; AssetFinderLOG.Log("Copied AssetFinderID Value: " + EditorGUIUtility.systemCopyBuffer); return true; } } partial class AssetUI { [NonSerialized] internal AssetNameContent nameContent; [NonSerialized] internal AssetPathContent pathContent; public void DrawAssetPath(ref Rect rect) { if (this == NO_PARENT) return; if (pathContent == null) pathContent = new AssetPathContent(); if (!pathContent.isValid) pathContent.Refresh(path); using (AssetFinderGUI.Color(GUI.color.Alpha(0.5f))) { Rect pathRect = GUI2.LeftRect(pathContent.pathWidth, ref rect); GUI.Label(pathRect, pathContent.pathContent, EditorStyles.label); } } public void DrawAsset(ref Rect rect, bool withExt, bool withPath) { if (withPath) { AssetUI p = Parent; if (p != NO_PARENT) p.DrawAssetPath(ref rect); } // Draw AssetIcon Rect iconRect = GUI2.LeftRect(16f, ref rect); if (Event.current.type == EventType.Repaint) { Texture icon = AssetDatabase.GetCachedIcon(path); if (icon != null) GUI.DrawTexture(iconRect, icon, ScaleMode.ScaleToFit); } // Draw AssetName if (nameContent == null) nameContent = new AssetNameContent(); if (!nameContent.isValid) nameContent.Refresh(path); Rect nameRect = GUI2.LeftRect(nameContent.nameWidth, ref rect); GUI.Label(nameRect, nameContent.nameContent, EditorStyles.label); // Draw extension if (!withExt || !nameContent.hasExt) return; using (AssetFinderGUI.Color(GUI.color.Alpha(0.5f))) { Rect extRect = GUI2.LeftRect(nameContent.extWidth, ref rect); GUI.Label(extRect, nameContent.extContent, EditorStyles.label); } } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/UI/AssetUI.cs.meta ================================================ fileFormatVersion: 2 guid: e5625265bccf4ca78a1745e92a5903b0 timeCreated: 1737956390 ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/UI/FileUI.cs ================================================ namespace VirtueSky.AssetFinder.Editor { internal class FileUI : AssetUI { internal FileUI(string guid, string path) : base(guid, path){} // Draw all subAssets??? } } ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/UI/FileUI.cs.meta ================================================ fileFormatVersion: 2 guid: 4d14b3d72c054a9fbbd8ee474864fb39 timeCreated: 1737957263 ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/UI/FolderUI.cs ================================================ namespace VirtueSky.AssetFinder.Editor { internal class FolderUI : AssetUI { internal FolderUI(string guid, string path) : base(guid, path){} } } ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/UI/FolderUI.cs.meta ================================================ fileFormatVersion: 2 guid: b48108ae49c7431f8485fd4b3dd5371d timeCreated: 1737955553 ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/UI.meta ================================================ fileFormatVersion: 2 guid: 27ba266e29bc4c20bb9dbf1ec684ea9b timeCreated: 1737955455 ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/Unity/AssetFinderInitializer.cs ================================================ using UnityEditor; using UnityEngine; namespace VirtueSky.AssetFinder.Editor { public static class AssetFinderInitializer { [InitializeOnLoadMethod] static void Init() { EditorApplication.update -= DelayInit; EditorApplication.update += DelayInit; AssemblyReloadEvents.afterAssemblyReload -= Reload; AssemblyReloadEvents.afterAssemblyReload += Reload; EditorApplication.playModeStateChanged -= OnPlayModeStateChanged; EditorApplication.playModeStateChanged += OnPlayModeStateChanged; } private static void OnPlayModeStateChanged(PlayModeStateChange state) { switch (state) { case PlayModeStateChange.EnteredPlayMode: break; case PlayModeStateChange.EnteredEditMode: { Reload(); if (AssetFinderCache.Api != null && !AssetFinderSettingExt.disable) { AssetFinderCache.Api.IncrementalRefresh(); } break; } } } static void Reload() { AssetFinderAddressable.Scan(); AssetFinderCache.Reload(); // Re-init all windows var allWindows = Resources.FindObjectsOfTypeAll(); for (var i = 0; i < allWindows.Length; i++) { allWindows[i].Reload(); } } static void DelayInit() { if (EditorApplication.isCompiling || EditorApplication.isUpdating) { AssetFinderLOG.Log("Keep waiting..."); return; } EditorApplication.update -= DelayInit; // Simple type search scoped to Assets/ only string[] cache = AssetDatabase.FindAssets("t:AssetFinderCacheAsset", new[] { "Assets" }); if (cache.Length == 0) { return; // No cache found } // Try to load the first valid cache asset for (int i = 0; i < cache.Length; i++) { string assetPath = AssetDatabase.GUIDToAssetPath(cache[i]); if (string.IsNullOrEmpty(assetPath)) continue; var cache0 = AssetDatabase.LoadAssetAtPath(assetPath); if (cache0 != null) { AssetFinderCacheAsset.Init(cache0); return; } } AssetFinderLOG.LogWarning("FR2: Cache assets found but all failed to load!"); } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/Unity/AssetFinderInitializer.cs.meta ================================================ fileFormatVersion: 2 guid: b745caddec1cd2542b746816dd28ed55 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/Unity/AssetFinderLightmap.cs ================================================ // deleted ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/Unity/AssetFinderLightmap.cs.meta ================================================ fileFormatVersion: 2 guid: 4cba24c6726bc5648b3b290eb439584d MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/Unity/AssetFinderTerrain.cs ================================================ using System; using System.Collections; using System.Collections.Generic; using UnityEngine; namespace VirtueSky.AssetFinder.Editor { internal static class AssetFinderTerrain { [Serializable] internal class TerrainTextureData { public Texture2D[] textures; public TerrainTextureData(params Texture2D[] param) { var count = 0; if (param != null) count = param.Length; textures = new Texture2D[count]; for (var i = 0; i < count; i++) { textures[i] = param[i]; } } } internal static int ReplaceTerrainTextureDatas(TerrainData terrain, Texture2D fromObj, Texture2D toObj) { var found = 0; #if UNITY_2018_3_OR_NEWER TerrainLayer[] arr3 = terrain.terrainLayers; for (var i = 0; i < arr3.Length; i++) { if (arr3[i].normalMapTexture == fromObj) { found++; arr3[i].normalMapTexture = toObj; } if (arr3[i].maskMapTexture == fromObj) { found++; arr3[i].maskMapTexture = toObj; } if (arr3[i].diffuseTexture == fromObj) { found++; arr3[i].diffuseTexture = toObj; } } terrain.terrainLayers = arr3; #else var arr3 = terrain.splatPrototypes; for (var i = 0; i < arr3.Length; i++) { if (arr3[i].texture == fromObj) { found++; arr3[i].texture = toObj; } if (arr3[i].normalMap == fromObj) { found++; arr3[i].normalMap = toObj; } } terrain.splatPrototypes = arr3; #endif return found; } internal static TerrainTextureData[] GetTerrainTextureDatas(TerrainData data) { #if UNITY_2018_3_OR_NEWER if (data == null || data.terrainLayers == null) { return new TerrainTextureData[] { }; } var arr = new TerrainTextureData[data.terrainLayers.Length]; for (var i = 0; i < data.terrainLayers.Length; i++) { TerrainLayer layer = data.terrainLayers[i]; arr[i] = layer == null ? new TerrainTextureData() : new TerrainTextureData( layer.normalMapTexture, layer.maskMapTexture, layer.diffuseTexture ); } return arr; #else var arr = new TerrainTextureData[data.splatPrototypes.Length]; for(int i = 0; i < data.splatPrototypes.Length; i++) { var layer = data.splatPrototypes[i]; arr[i] = new TerrainTextureData ( layer.normalMap, layer.texture ); } return arr; #endif } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/Unity/AssetFinderTerrain.cs.meta ================================================ fileFormatVersion: 2 guid: 63dd5db1ae5552847acf741487c1af2e MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/Unity/AssetFinderUSelection.cs ================================================ using System.Text; using UnityEditor; using UnityEngine; namespace VirtueSky.AssetFinder.Editor { public static class AssetFinderUSelection { private static readonly StringBuilder sb = new StringBuilder(); internal static void StartDebugReference() { Selection.selectionChanged -= DebugAssetReference; Selection.selectionChanged += DebugAssetReference; } internal static void StopDebugReference() { Selection.selectionChanged -= DebugAssetReference; } private static void DebugAssetReference() { if (!AssetFinderCacheAsset.isReady) return; Object activeObject = Selection.activeObject; if (activeObject == null) return; AssetDatabase.TryGetGUIDAndLocalFileIdentifier(activeObject, out string guid, out long fileId); var isMainAsset = AssetDatabase.IsMainAsset(activeObject); var usageList = AssetFinderCacheAsset.CollectUsage(guid); var usedByList = AssetFinderCacheAsset.CollectUsedBy(guid, isMainAsset ? -1 : fileId); sb.Clear(); sb.AppendLine($"{guid}:{fileId} : {AssetDatabase.GUIDToAssetPath(guid)}"); sb.AppendLine($"Used: {usageList.Count}\n"); for (var i = 0; i < usageList.Count; i++) { AssetFinderIDRef usage = usageList[i]; var (useGUID, useFileId) = AssetFinderCacheAsset.GetGuidAndFileId(usage.toId); sb.AppendLine($"{useGUID}:{useFileId} - {usage} \t\t {AssetDatabase.GUIDToAssetPath(useGUID)}"); } sb.AppendLine($"UsedBy: {usedByList.Count}\n"); for (var i = 0; i < usedByList.Count; i++) { AssetFinderIDRef useBy = usedByList[i]; var (useByGUID, _) = AssetFinderCacheAsset.GetGuidAndFileId(useBy.fromId); sb.AppendLine($"{useByGUID} - {useBy} \t\t {AssetDatabase.GUIDToAssetPath(useByGUID)}"); } Debug.Log(sb.ToString()); } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/Unity/AssetFinderUSelection.cs.meta ================================================ fileFormatVersion: 2 guid: 25969e281a1de8b48b8c1191090539a3 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/Unity.meta ================================================ fileFormatVersion: 2 guid: 1704823120c14e9ebb9eb9d5ae580068 timeCreated: 1730993756 ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/Utils/AssetFinderTimeSlice.cs ================================================ #define AssetFinderDEBUG using System; using UnityEditor; using UnityEngine; namespace VirtueSky.AssetFinder.Editor { public class AssetFinderTimeSlice { private readonly Action onCompleteCallback; private readonly Action processingAction; private readonly Func targetCountFunc; private int currentIndex; public readonly float timeSlice = 1 / 100f; public AssetFinderTimeSlice(Func countFunc, Action action, Action onComplete = null) { targetCountFunc = countFunc; processingAction = action; onCompleteCallback = onComplete; } public void Start() { currentIndex = 0; EditorApplication.update += ProcessQueue; } public void Stop() { EditorApplication.update -= ProcessQueue; } private void ProcessQueue() { float startTime = Time.realtimeSinceStartup; int targetCount = targetCountFunc.Invoke(); // Process items within the time slice while (currentIndex < targetCount) { processingAction.Invoke(currentIndex); currentIndex++; if (Time.realtimeSinceStartup - startTime >= timeSlice) { #if AssetFinderDEBUG float pct = currentIndex * 100f / targetCount; AssetFinderLOG.Log($"Progress: {pct:0.00}% - {currentIndex}/{targetCount}"); #endif return; } } targetCount = targetCountFunc.Invoke(); // Stop processing if we've reached the target count if (currentIndex < targetCount) return; EditorApplication.update -= ProcessQueue; onCompleteCallback?.Invoke(); } } } ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/Utils/AssetFinderTimeSlice.cs.meta ================================================ fileFormatVersion: 2 guid: 93892da2f0d8ba448909a3fed223cc0a MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor/v2/Utils.meta ================================================ fileFormatVersion: 2 guid: fc17651b6a294c0897caad1ae823f6d1 timeCreated: 1730992938 ================================================ FILE: VirtueSky/AssetFinder/Editor/v2.meta ================================================ fileFormatVersion: 2 guid: 8e5457f2d0edd449e939840c60b51a84 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder/Editor.meta ================================================ fileFormatVersion: 2 guid: 60f91a6c3e6d33542af8e8d8aca5178e folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/AssetFinder.meta ================================================ fileFormatVersion: 2 guid: ad1cc3dbf7ddd174b8e4d79693c7e3c3 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Audio/Editor/AudioWindowEditor.cs ================================================ #if UNITY_EDITOR using UnityEditor; using VirtueSky.Audio; using VirtueSky.UtilsEditor; namespace VirtueSky.AudioEditor { public class AudioWindowEditor : EditorWindow { public static void CreateSoundData() { CreateAsset.CreateScriptableAssetsOnlyName("/Audio/SoundData", "sound_data"); } #region Event Music public static void CreatePlayMusicEvent() { CreateAsset.CreateScriptableAssets("/Audio/Music_Event", "play_music_event"); } public static void CreatePauseMusicEvent() { CreateAsset.CreateScriptableAssets("/Audio/Music_Event", "pause_music_event"); } public static void CreateResumeMusicEvent() { CreateAsset.CreateScriptableAssets("/Audio/Music_Event", "resume_music_event"); } public static void CreateStopMusicEvent() { CreateAsset.CreateScriptableAssets("/Audio/Music_Event", "stop_music_event"); } #endregion #region Event Sfx public static void CreatePlaySfxEvent() { CreateAsset.CreateScriptableAssets("/Audio/Sfx_Event", "play_sfx_event"); } public static void CreatePauseSfxEvent() { CreateAsset.CreateScriptableAssets("/Audio/Sfx_Event", "pause_sfx_event"); } public static void CreateFinishSfxEvent() { CreateAsset.CreateScriptableAssets("/Audio/Sfx_Event", "finish_sfx_event"); } public static void CreateResumeSfxEvent() { CreateAsset.CreateScriptableAssets("/Audio/Sfx_Event", "resume_sfx_event"); } public static void CreateStopSfxEvent() { CreateAsset.CreateScriptableAssets("/Audio/Sfx_Event", "stop_sfx_event"); } public static void CreateStopAllSfxEvent() { CreateAsset.CreateScriptableAssets("/Audio/Sfx_Event", "stop_all_sfx_event"); } #endregion #region Volume Change public static void CreateMusicVolume() { CreateAsset.CreateScriptableAssets("/Audio/Volume_Change", "music_volume"); } public static void CreateSfxVolume() { CreateAsset.CreateScriptableAssets("/Audio/Volume_Change", "sfx_volume"); } #endregion } } #endif ================================================ FILE: VirtueSky/Audio/Editor/AudioWindowEditor.cs.meta ================================================ fileFormatVersion: 2 guid: 5dbf320248604081a9cb6de994848425 timeCreated: 1697699209 ================================================ FILE: VirtueSky/Audio/Editor/EditorAudioPreview.cs ================================================ using UnityEditor; using UnityEngine; using System; using System.Reflection; namespace VirtueSky.AudioEditor { internal static class EditorAudioPreview { static readonly Type AudioUtilType; static readonly MethodInfo PlayMethod; static readonly MethodInfo StopAllMethod; static readonly MethodInfo StopOneMethod; // Hỗ trợ nhiều biến thể kiểm tra trạng thái phát static readonly MethodInfo IsPlayingClipMethod; // IsPreviewClipPlaying(AudioClip) static readonly MethodInfo IsPlayingNoArgMethod; // IsPreviewClipPlaying() static readonly MethodInfo GetPreviewClipMethod; // GetPreviewClip() static EditorAudioPreview() { AudioUtilType = typeof(AudioImporter).Assembly.GetType("UnityEditor.AudioUtil"); var flags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; // PlayPreviewClip(clip, startSample, loop[, honorPlayOneShot?]) PlayMethod = AudioUtilType.GetMethod("PlayPreviewClip", flags, null, new Type[] { typeof(AudioClip), typeof(int), typeof(bool) }, null) ?? AudioUtilType.GetMethod("PlayPreviewClip", flags, null, new Type[] { typeof(AudioClip), typeof(int), typeof(bool), typeof(bool) }, null); StopAllMethod = AudioUtilType.GetMethod("StopAllPreviewClips", flags); StopOneMethod = AudioUtilType.GetMethod("StopPreviewClip", flags, null, new Type[] { typeof(AudioClip) }, null); IsPlayingClipMethod = AudioUtilType.GetMethod("IsPreviewClipPlaying", flags, null, new Type[] { typeof(AudioClip) }, null); IsPlayingNoArgMethod = AudioUtilType.GetMethod("IsPreviewClipPlaying", flags, null, Type.EmptyTypes, null); GetPreviewClipMethod = AudioUtilType.GetMethod("GetPreviewClip", flags); } public static void Play(AudioClip clip, bool loop = false, int startSample = 0) { if (!clip || PlayMethod == null) return; var args = PlayMethod.GetParameters().Length == 3 ? new object[] { clip, startSample, loop } : new object[] { clip, startSample, loop, false }; PlayMethod.Invoke(null, args); } public static void Stop(AudioClip clip = null) { if (clip != null && StopOneMethod != null) StopOneMethod.Invoke(null, new object[] { clip }); else if (StopAllMethod != null) StopAllMethod.Invoke(null, null); } public static bool IsPlaying(AudioClip clip = null) { try { if (IsPlayingClipMethod != null) return (bool)IsPlayingClipMethod.Invoke(null, new object[] { clip }); if (IsPlayingNoArgMethod != null) return (bool)IsPlayingNoArgMethod.Invoke(null, null); if (GetPreviewClipMethod != null) { var cur = GetPreviewClipMethod.Invoke(null, null) as AudioClip; return clip ? cur == clip : cur != null; } } catch { /* ignore reflection issues */ } return false; } } } ================================================ FILE: VirtueSky/Audio/Editor/EditorAudioPreview.cs.meta ================================================ fileFormatVersion: 2 guid: 1b9f795e3e2e4b72a0f5911284392590 timeCreated: 1757940109 ================================================ FILE: VirtueSky/Audio/Editor/SoundDataEditor.cs ================================================ using System; using System.Collections.Generic; using UnityEditor; using UnityEngine; using VirtueSky.Audio; using VirtueSky.UtilsEditor; namespace VirtueSky.AudioEditor { [CustomEditor(typeof(SoundData))] public class SoundDataEditor : Editor { SerializedProperty clipsProp; // State preview int selectedIndex = 0; float playheadSec = 0f; float loopA = -1f, loopB = -1f; bool selectingLoop = false; AudioClip activeClip; AudioClip lastPlayed; double lastTickTime; bool isPlaying = false; int lastKnownSamplePosition = 0; Action externalRepaintCallback; public void SetExternalRepaintCallback(Action callback) { externalRepaintCallback = callback; } const float TimebarH = 22f; const float LaneH = 38f; void OnEnable() { clipsProp = serializedObject.FindProperty("audioClips"); EditorApplication.update += OnEditorUpdate; } void OnDisable() { EditorApplication.update -= OnEditorUpdate; isPlaying = false; EditorAudioPreview.Stop(); lastPlayed = null; activeClip = null; externalRepaintCallback = null; } void RequestRepaint() { base.Repaint(); externalRepaintCallback?.Invoke(); } GUIStyle StyleLabel() { var style = new GUIStyle(); style.fontSize = 14; style.normal.textColor = Color.white; return style; } public override void OnInspectorGUI() { DrawDefaultInspector(); EditorGUILayout.Space(10); Uniform.DrawGroupFoldout("preview_sound_data", "Editor Preview", DrawPreview, true); serializedObject.Update(); serializedObject.ApplyModifiedProperties(); } void DrawPreview() { int total = clipsProp != null ? clipsProp.arraySize : 0; if (total <= 0) { EditorGUILayout.HelpBox("Add AudioClip to preview.", MessageType.Info); return; } List indexMap = new List(total); List options = new List(total); for (int i = 0; i < total; i++) { var el = clipsProp.GetArrayElementAtIndex(i); var clip = el.objectReferenceValue as AudioClip; if (clip != null) { indexMap.Add(i); options.Add($"{i} - {clip.name}"); } } if (indexMap.Count == 0) { EditorGUILayout.HelpBox( "The AudioClips list has elements but they are all null. Drag and drop AudioClips into it or delete the null elements.", MessageType.Info ); if (isPlaying) { isPlaying = false; EditorAudioPreview.Stop(); lastPlayed = null; activeClip = null; } return; } selectedIndex = Mathf.Clamp(selectedIndex, 0, indexMap.Count - 1); int newSel = EditorGUILayout.Popup("Preview Clip", selectedIndex, options.ToArray()); int propIndex = indexMap[newSel]; var selEl = clipsProp.GetArrayElementAtIndex(propIndex); var sel = selEl.objectReferenceValue as AudioClip; if (newSel != selectedIndex || sel != activeClip) { isPlaying = false; EditorAudioPreview.Stop(activeClip); selectedIndex = newSel; activeClip = sel; playheadSec = 0f; lastPlayed = null; } using (new EditorGUI.DisabledScope(activeClip == null)) { DrawTimeline(activeClip); DrawTransport(activeClip); } } /// /// Update per frame when editor is active /// void OnEditorUpdate() { if (!activeClip || !isPlaying) return; // Sync playhead with actual audio playback position float actualPosition = GetAudioPreviewPosition(activeClip); if (actualPosition >= 0f) { playheadSec = actualPosition; } else { // Fallback to time-based calculation if position can't be retrieved double now = EditorApplication.timeSinceStartup; double dt = System.Math.Max(0, now - lastTickTime); lastTickTime = now; playheadSec += (float)dt; } if (HasLoop()) { float a = Mathf.Min(loopA, loopB); float b = Mathf.Max(loopA, loopB); if (playheadSec > b) { playheadSec = a; if (isPlaying) { int startSample = Mathf.Clamp(Mathf.RoundToInt(a * activeClip.frequency), 0, activeClip.samples - 1); EditorAudioPreview.Play(activeClip, false, startSample); lastTickTime = EditorApplication.timeSinceStartup; } } } else if (playheadSec > activeClip.length) { // Auto-return to 0 and stop isPlaying = false; EditorAudioPreview.Stop(activeClip); lastPlayed = null; playheadSec = 0f; } // Always repaint when playing to ensure smooth animation RequestRepaint(); } /// /// Get current audio preview position using reflection /// float GetAudioPreviewPosition(AudioClip clip) { if (clip == null) return -1f; try { var unityEditorAssembly = typeof(AudioImporter).Assembly; var audioUtilClass = unityEditorAssembly.GetType("UnityEditor.AudioUtil"); // Try to get the playing sample position var method = audioUtilClass.GetMethod("GetClipSamplePosition", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public); if (method != null) { var result = method.Invoke(null, new object[] { clip }); if (result != null) { int samplePosition = (int)result; if (samplePosition >= 0 && clip.frequency > 0) { return (float)samplePosition / clip.frequency; } } } } catch { // Fallback to time-based calculation } return -1f; } // ====== Timeline UI ====== void DrawTimeline(AudioClip clip) { // Timebar (ticks) var timeRect = GUILayoutUtility.GetRect(0, 1000, TimebarH, TimebarH); EditorGUI.DrawRect(timeRect, new Color(0.11f, 0.11f, 0.11f)); DrawTicks(timeRect, clip.length); // Lane (playhead + loop A–B) var laneRect = GUILayoutUtility.GetRect(0, 1000, LaneH, LaneH); EditorGUI.DrawRect(laneRect, new Color(0.09f, 0.09f, 0.09f)); if (HasLoop()) { float a = Mathf.Clamp(Mathf.Min(loopA, loopB), 0, clip.length); float b = Mathf.Clamp(Mathf.Max(loopA, loopB), 0, clip.length); var r = TimeRangeToRect(laneRect, 0, clip.length, a, b); EditorGUI.DrawRect(r, new Color(0.2f, 0.6f, 0.3f, 0.20f)); DrawBorder(r, new Color(0.3f, 0.9f, 0.5f, 0.85f)); } // Playhead float px = TimeToPixel(laneRect, 0, clip.length, playheadSec); EditorGUI.DrawRect(new Rect(px, laneRect.y, 2f, laneRect.height), new Color(1f, 0.85f, 0.2f)); HandleLaneInput(laneRect, clip.length); } void DrawTransport(AudioClip clip) { using (new EditorGUILayout.HorizontalScope()) { string playLabel = isPlaying ? "Restart" : "Play from Head"; if (GUILayout.Button(playLabel, GUILayout.Height(22))) { if (clip) { if (isPlaying) { EditorAudioPreview.Stop(clip); playheadSec = 0f; lastKnownSamplePosition = 0; } if (lastPlayed && lastPlayed != clip) EditorAudioPreview.Stop(lastPlayed); lastPlayed = clip; isPlaying = true; int startSample = Mathf.Clamp(Mathf.RoundToInt(playheadSec * clip.frequency), 0, clip.samples - 1); lastKnownSamplePosition = startSample; EditorAudioPreview.Play(clip, false, startSample); lastTickTime = EditorApplication.timeSinceStartup; } } if (GUILayout.Button("Stop", GUILayout.Height(22))) { if (clip) { isPlaying = false; EditorAudioPreview.Stop(); lastPlayed = null; playheadSec = 0f; // Reset playhead to beginning when stopped RequestRepaint(); } } if (GUILayout.Button("To Start", GUILayout.Height(22))) { if (clip) { playheadSec = 0f; lastKnownSamplePosition = 0; if (isPlaying) { EditorAudioPreview.Play(clip, false, 0); lastTickTime = EditorApplication.timeSinceStartup; } else { RequestRepaint(); // Only repaint if not playing to update the UI } } } if (GUILayout.Button("↺ Set Loop A", GUILayout.Height(22))) { if (clip) loopA = Mathf.Clamp(playheadSec, 0, clip.length); } if (GUILayout.Button("↻ Set Loop B", GUILayout.Height(22))) { if (clip) loopB = Mathf.Clamp(playheadSec, 0, clip.length); } if (GUILayout.Button("Set Loop Full", GUILayout.Height(22))) { if (clip) { loopA = 0f; loopB = clip.length; if (isPlaying) { playheadSec = 0f; lastKnownSamplePosition = 0; EditorAudioPreview.Play(clip, false, 0); lastTickTime = EditorApplication.timeSinceStartup; } else { RequestRepaint(); // Only repaint if not playing to update the UI } } } if (GUILayout.Button("Clear Loop", GUILayout.Height(22))) { loopA = loopB = -1f; RequestRepaint(); // Repaint to update the UI immediately } } EditorGUILayout.LabelField( $"Clip: {clip.name} • Length: {clip.length:0.000}s • Head: {playheadSec:0.000}s" + (HasLoop() ? $" • Loop [{Mathf.Min(loopA, loopB):0.000} – {Mathf.Max(loopA, loopB):0.000}]s" : "") ); EditorGUILayout.HelpBox( "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).", MessageType.Info ); } // ====== Helpers ====== bool HasLoop() => loopA >= 0f && loopB >= 0f && !Mathf.Approximately(loopA, loopB); void HandleLaneInput(Rect r, float len) { var e = Event.current; if (!r.Contains(e.mousePosition) || len <= 0f) return; if (e.type == EventType.MouseDown && e.button == 0) { playheadSec = Mathf.Clamp(PixelToTime(r, 0, len, e.mousePosition.x), 0, len); // When user manually sets the playhead, update the audio preview if (isPlaying && activeClip) { int startSample = Mathf.Clamp(Mathf.RoundToInt(playheadSec * activeClip.frequency), 0, activeClip.samples - 1); lastKnownSamplePosition = startSample; EditorAudioPreview.Play(activeClip, false, startSample); lastTickTime = EditorApplication.timeSinceStartup; } e.Use(); RequestRepaint(); // Force repaint immediately to update the UI } else if (e.type == EventType.MouseDrag && e.button == 0) { playheadSec = Mathf.Clamp(PixelToTime(r, 0, len, e.mousePosition.x), 0, len); // When dragging the playhead, update the audio preview to match the position if (isPlaying && activeClip) { int startSample = Mathf.Clamp(Mathf.RoundToInt(playheadSec * activeClip.frequency), 0, activeClip.samples - 1); lastKnownSamplePosition = startSample; EditorAudioPreview.Play(activeClip, false, startSample); lastTickTime = EditorApplication.timeSinceStartup; } e.Use(); RequestRepaint(); // Force repaint immediately to update the UI } if (e.type == EventType.MouseDown && e.button == 1) { loopA = loopB = Mathf.Clamp(PixelToTime(r, 0, len, e.mousePosition.x), 0, len); selectingLoop = true; e.Use(); } else if (e.type == EventType.MouseDrag && e.button == 1 && selectingLoop) { loopB = Mathf.Clamp(PixelToTime(r, 0, len, e.mousePosition.x), 0, len); e.Use(); } else if (e.type == EventType.MouseUp && e.button == 1 && selectingLoop) { selectingLoop = false; e.Use(); } } void DrawTicks(Rect r, float total) { if (total <= 0f) return; float step = NiceStep(total); Handles.BeginGUI(); Handles.color = new Color(0.6f, 0.6f, 0.6f, 0.7f); for (float t = 0f; t <= total + 0.0001f; t += step) { float x = Mathf.Lerp(r.x, r.xMax, t / total); Handles.DrawLine(new Vector2(x, r.y), new Vector2(x, r.yMax)); } Handles.EndGUI(); // Vẽ nhãn sau để tránh chồng chéo vá»›i các đường kẻ for (float t = 0f; t <= total + 0.0001f; t += step) { float x = Mathf.Lerp(r.x, r.xMax, t / total); var label = $"{t:0.00}s"; var size = GUI.skin.label.CalcSize(new GUIContent(label)); GUI.Label(new Rect(x + 2, r.y - 1, size.x, r.height), label); } } float NiceStep(float total) { float[] steps = { 0.05f, 0.1f, 0.2f, 0.5f, 1f, 2f, 5f, 10f, 15f, 30f, 60f }; foreach (var s in steps) if (total / s <= 12f) return s; return 120f; } float TimeToPixel(Rect r, float start, float end, float t) { float u = Mathf.InverseLerp(start, end, t); return Mathf.Lerp(r.x, r.xMax, u); } float PixelToTime(Rect r, float start, float end, float px) { float u = Mathf.InverseLerp(r.x, r.xMax, px); return Mathf.Lerp(start, end, u); } Rect TimeRangeToRect(Rect r, float start, float end, float a, float b) { float ax = TimeToPixel(r, start, end, a); float bx = TimeToPixel(r, start, end, b); return Rect.MinMaxRect(Mathf.Min(ax, bx), r.y, Mathf.Max(ax, bx), r.yMax); } void DrawBorder(Rect r, Color c) { EditorGUI.DrawRect(new Rect(r.x, r.y, r.width, 2), c); EditorGUI.DrawRect(new Rect(r.x, r.yMax - 2, r.width, 2), c); EditorGUI.DrawRect(new Rect(r.x, r.y, 2, r.height), c); EditorGUI.DrawRect(new Rect(r.xMax - 2, r.y, 2, r.height), c); } } } ================================================ FILE: VirtueSky/Audio/Editor/SoundDataEditor.cs.meta ================================================ fileFormatVersion: 2 guid: 087c7c60e1b14a94ad7af200a4fbd940 timeCreated: 1757940241 ================================================ FILE: VirtueSky/Audio/Editor/Virtuesky.Sunflower.Audio.Editor.asmdef ================================================ { "name": "Virtuesky.Sunflower.Audio.Editor", "rootNamespace": "", "references": [ "GUID:2ba9ab3e4292d6e4b81f0022dc854eee", "GUID:c904f6d969e991d459a0843b71c22ec5", "GUID:acb3cac55c622ec459c8caadf707623a", "GUID:bd40169efe8642149b1d2b72ba4903ce", "GUID:ce8c6e3f188ed064f933ef35b46bf8bd", "GUID:35d694408290717499b3838802212c7f" ], "includePlatforms": [ "Editor" ], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], "versionDefines": [], "noEngineReferences": false } ================================================ FILE: VirtueSky/Audio/Editor/Virtuesky.Sunflower.Audio.Editor.asmdef.meta ================================================ fileFormatVersion: 2 guid: dcf049c718e6d4d0b8bbcaf56be706c2 AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Audio/Editor.meta ================================================ fileFormatVersion: 2 guid: c0b59c1b97996ee4f851fa88c2b8a3c6 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Audio/Runtime/AudioHelper.cs ================================================ namespace VirtueSky.Audio { public static class AudioHelper { public static SoundCache PlaySfx(this SoundData soundData, PlaySfxEvent playSfxEvent) => playSfxEvent.Raise(soundData); public static void PauseSfx(this SoundCache soundCache, PauseSfxEvent pauseSfxEvent) => pauseSfxEvent.Raise(soundCache); public static void StopSfx(this SoundCache soundCache, StopSfxEvent stopSfxEvent) => stopSfxEvent.Raise(soundCache); public static void ResumeSfx(this SoundCache soundCache, ResumeSfxEvent resumeSfxEvent) => resumeSfxEvent.Raise(soundCache); public static void FinishSfx(this SoundCache soundCache, FinishSfxEvent finishSfxEvent) => finishSfxEvent.Raise(soundCache); public static void StopAllSfx(this StopAllSfxEvent stopAllSfxEvent) => stopAllSfxEvent.Raise(); public static void PlayMusic(this SoundData soundData, PlayMusicEvent playMusicEvent) => playMusicEvent.Raise(soundData); public static void StopMusic(this StopMusicEvent stopMusicEvent) => stopMusicEvent.Raise(); public static void PauseMusic(this PauseMusicEvent pauseMusicEvent) => pauseMusicEvent.Raise(); public static void ResumeMusic(this ResumeMusicEvent resumeMusicEvent) => resumeMusicEvent.Raise(); } } ================================================ FILE: VirtueSky/Audio/Runtime/AudioHelper.cs.meta ================================================ fileFormatVersion: 2 guid: c28340e8673e4449905ac4eafb9b8bb1 timeCreated: 1727858865 ================================================ FILE: VirtueSky/Audio/Runtime/AudioManager.cs ================================================ using System.Collections.Generic; using System.Linq; using UnityEngine; using VirtueSky.Core; using VirtueSky.DataType; using VirtueSky.Inspector; using VirtueSky.ObjectPooling; using VirtueSky.Utils; #if UNITY_EDITOR using VirtueSky.UtilsEditor; #endif namespace VirtueSky.Audio { [EditorIcon("icon_sound_mixer"), HideMonoScript] public class AudioManager : BaseMono { [Space] [SerializeField] private bool isDontDestroyOnLoad; [SerializeField] private SoundComponent soundComponentPrefab; [SerializeField] private Transform audioHolder; [Space] [TitleColor("Music Listening", CustomColor.Aqua, CustomColor.Lime)] [SerializeField] private PlayMusicEvent eventPlayMusic; [SerializeField] private StopMusicEvent eventStopMusic; [SerializeField] private PauseMusicEvent eventPauseMusic; [SerializeField] private ResumeMusicEvent eventResumeMusic; [Space] [TitleColor("Sfx Listening", CustomColor.Orange, CustomColor.Bisque)] [SerializeField] private PlaySfxEvent eventPlaySfx; [SerializeField] private StopSfxEvent eventStopSfx; [SerializeField] private PauseSfxEvent eventPauseSfx; [SerializeField] private ResumeSfxEvent eventResumeSfx; [SerializeField] private FinishSfxEvent eventFinishSfx; [SerializeField] private StopAllSfxEvent eventStopAllSfx; [Space] [TitleColor("AudioManager Settings", CustomColor.DeepSkyBlue, CustomColor.Salmon)] [SerializeField] private MusicVolumeChange musicVolume; [SerializeField] SfxVolumeChange sfxVolume; private SoundComponent music; [ReadOnly, SerializeField] private List listCacheSfx = new List(); private int key = 0; private void Awake() { if (isDontDestroyOnLoad) { DontDestroyOnLoad(this.gameObject); } sfxVolume.AddListener(OnSfxVolumeChanged); musicVolume.AddListener(OnMusicVolumeChanged); } public override void OnEnable() { base.OnEnable(); eventPlaySfx.AddListener(PlaySfx); eventStopSfx.AddListener(StopSfx); eventFinishSfx.AddListener(FinishSfx); eventResumeSfx.AddListener(ResumeSfx); eventPauseSfx.AddListener(PauseSfx); eventStopAllSfx.AddListener(StopAllSfx); eventPlayMusic.AddListener(PlayMusic); eventPauseMusic.AddListener(PauseMusic); eventResumeMusic.AddListener(ResumeMusic); eventStopMusic.AddListener(StopMusic); } public override void OnDisable() { base.OnDisable(); eventPlaySfx.RemoveListener(PlaySfx); eventStopSfx.RemoveListener(StopSfx); eventFinishSfx.RemoveListener(FinishSfx); eventResumeSfx.RemoveListener(ResumeSfx); eventPauseSfx.RemoveListener(PauseSfx); eventStopAllSfx.RemoveListener(StopAllSfx); eventPlayMusic.RemoveListener(PlayMusic); eventPauseMusic.RemoveListener(PauseMusic); eventResumeMusic.RemoveListener(ResumeMusic); eventStopMusic.RemoveListener(StopMusic); } void OnMusicVolumeChanged(float volume) { if (music != null) { music.Volume = volume; } } void OnSfxVolumeChanged(float volume) { for (var i = 0; i < listCacheSfx.Count; i++) { listCacheSfx[i].Volume = volume; } } #region Sfx private SoundCache PlaySfx(SoundData soundData) { var sfxComponent = soundComponentPrefab.Spawn(audioHolder); sfxComponent.PlayAudioClip(soundData.GetAudioClip(), soundData.loop, soundData.volume * sfxVolume.Value); if (!soundData.loop) sfxComponent.OnCompleted += OnFinishPlayingAudio; SoundCache soundCache = GetSoundCache(soundData); sfxComponent.Key = key; listCacheSfx.Add(sfxComponent); return soundCache; } private void StopSfx(SoundCache soundCache) { var soundComponent = GetSoundComponent(soundCache); if (soundComponent == null) return; StopAndCleanAudioComponent(soundComponent); } private void PauseSfx(SoundCache soundCache) { var soundComponent = GetSoundComponent(soundCache); if (soundComponent == null || !soundComponent.IsPlaying) return; soundComponent.Pause(); } private void ResumeSfx(SoundCache soundCache) { var soundComponent = GetSoundComponent(soundCache); if (soundComponent == null || soundComponent.IsPlaying) return; soundComponent.Resume(); } private void FinishSfx(SoundCache soundCache) { var soundComponent = GetSoundComponent(soundCache); if (soundComponent == null || !soundComponent.IsPlaying) return; soundComponent.Finish(); soundComponent.OnCompleted += OnFinishPlayingAudio; } private void StopAllSfx() { var listTemp = listCacheSfx.ToList(); for (int i = 0; i < listTemp.Count; i++) { StopAndCleanAudioComponent(listTemp[i]); } listCacheSfx.Clear(); listTemp.Clear(); key = 0; } #endregion #region Music private void PlayMusic(SoundData soundData) { if (music == null || !music.IsPlaying) { music = soundComponentPrefab.Spawn(audioHolder); } music.FadePlayMusic(soundData.GetAudioClip(), soundData.loop, soundData.volume * musicVolume.Value, soundData.isMusicFadeVolume, soundData.fadeOutDuration, soundData.fadeInDuration); music.OnCompleted += StopAudioMusic; } private void StopMusic() { if (music != null && music.IsPlaying) { music.Stop(); music.gameObject.DeSpawn(); } } private void PauseMusic() { if (music != null && music.IsPlaying) { music.Pause(); } } private void ResumeMusic() { if (music != null && !music.IsPlaying) { music.Resume(); } } #endregion void OnFinishPlayingAudio(SoundComponent soundComponent) { StopAndCleanAudioComponent(soundComponent); } void StopAndCleanAudioComponent(SoundComponent soundComponent) { if (!soundComponent.IsLooping) { soundComponent.OnCompleted -= OnFinishPlayingAudio; } soundComponent.Stop(); soundComponent.gameObject.DeSpawn(); if (listCacheSfx.Contains(soundComponent)) listCacheSfx.Remove(soundComponent); } void StopAudioMusic(SoundComponent soundComponent) { soundComponent.OnCompleted -= StopAudioMusic; soundComponent.gameObject.DeSpawn(); } SoundComponent GetSoundComponent(SoundCache soundCache) { if (soundCache == null) return null; for (var i = 0; i < listCacheSfx.Count; i++) { if (soundCache.key == listCacheSfx[i].Key) return listCacheSfx[i]; } return null; } SoundCache GetSoundCache(SoundData soundData) { key++; return new SoundCache(key, soundData); } #if UNITY_EDITOR private void Reset() { eventPlayMusic = CreateAsset.CreateAndGetScriptableAsset("/Audio/Music_Event", "play_music_event", false); eventPauseMusic = CreateAsset.CreateAndGetScriptableAsset("/Audio/Music_Event", "pause_music_event", false); eventResumeMusic = CreateAsset.CreateAndGetScriptableAsset("/Audio/Music_Event", "resume_music_event", false); eventStopMusic = CreateAsset.CreateAndGetScriptableAsset("/Audio/Music_Event", "stop_music_event", false); eventPlaySfx = CreateAsset.CreateAndGetScriptableAsset("/Audio/Sfx_Event", "play_sfx_event", false); eventPauseSfx = CreateAsset.CreateAndGetScriptableAsset("/Audio/Sfx_Event", "pause_sfx_event", false); eventFinishSfx = CreateAsset.CreateAndGetScriptableAsset("/Audio/Sfx_Event", "finish_sfx_event", false); eventResumeSfx = CreateAsset.CreateAndGetScriptableAsset("/Audio/Sfx_Event", "resume_sfx_event", false); eventStopSfx = CreateAsset.CreateAndGetScriptableAsset("/Audio/Sfx_Event", "stop_sfx_event", false); eventStopAllSfx = CreateAsset.CreateAndGetScriptableAsset("/Audio/Sfx_Event", "stop_all_sfx_event", false); musicVolume = CreateAsset.CreateAndGetScriptableAsset("/Audio/Volume_Change", "music_volume", false); sfxVolume = CreateAsset.CreateAndGetScriptableAsset("/Audio/Volume_Change", "sfx_volume", false); } #endif } } ================================================ FILE: VirtueSky/Audio/Runtime/AudioManager.cs.meta ================================================ fileFormatVersion: 2 guid: 82e25e7d80544a1d83bfd260713b1796 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 23fb672e22185124e935486385bd367e, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Audio/Runtime/Music_Event/PauseMusicEvent.cs ================================================ using UnityEngine; using VirtueSky.Events; using VirtueSky.Inspector; namespace VirtueSky.Audio { [CreateAssetMenu(menuName = "Sunflower/Audio/Music Event/Pause Music Event", fileName = "pause_music_event")] [EditorIcon("scriptable_audio")] public class PauseMusicEvent : EventNoParam { } } ================================================ FILE: VirtueSky/Audio/Runtime/Music_Event/PauseMusicEvent.cs.meta ================================================ fileFormatVersion: 2 guid: 6afe7f83f7204cc4863081a953b272fd MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: f6fa313956d229647ad5911f1b5d081a, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Audio/Runtime/Music_Event/PlayMusicEvent.cs ================================================ using UnityEngine; using VirtueSky.Events; using VirtueSky.Inspector; namespace VirtueSky.Audio { [CreateAssetMenu(menuName = "Sunflower/Audio/Music Event/Play Music Event", fileName = "play_music_event")] [EditorIcon("scriptable_audio")] public class PlayMusicEvent : BaseEvent { } } ================================================ FILE: VirtueSky/Audio/Runtime/Music_Event/PlayMusicEvent.cs.meta ================================================ fileFormatVersion: 2 guid: 8a62aa8ea2ab43eda9340c8c4f73ef33 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: f6fa313956d229647ad5911f1b5d081a, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Audio/Runtime/Music_Event/ResumeMusicEvent.cs ================================================ using UnityEngine; using VirtueSky.Events; using VirtueSky.Inspector; namespace VirtueSky.Audio { [CreateAssetMenu(menuName = "Sunflower/Audio/Music Event/Resume Music Event", fileName = "resume_music_event")] [EditorIcon("scriptable_audio")] public class ResumeMusicEvent : EventNoParam { } } ================================================ FILE: VirtueSky/Audio/Runtime/Music_Event/ResumeMusicEvent.cs.meta ================================================ fileFormatVersion: 2 guid: 0c8ea13bce9145d098ed6b23efa482fa MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: f6fa313956d229647ad5911f1b5d081a, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Audio/Runtime/Music_Event/StopMusicEvent.cs ================================================ using UnityEngine; using VirtueSky.Events; using VirtueSky.Inspector; namespace VirtueSky.Audio { [CreateAssetMenu(menuName = "Sunflower/Audio/Music Event/Stop Music Event", fileName = "stop_music_event")] [EditorIcon("scriptable_audio")] public class StopMusicEvent : EventNoParam { } } ================================================ FILE: VirtueSky/Audio/Runtime/Music_Event/StopMusicEvent.cs.meta ================================================ fileFormatVersion: 2 guid: 3f802843e01846d5b770835f611fe93f MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: f6fa313956d229647ad5911f1b5d081a, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Audio/Runtime/Music_Event.meta ================================================ fileFormatVersion: 2 guid: 5ecd74fd5ac547138187235af28e29ba timeCreated: 1708586749 ================================================ FILE: VirtueSky/Audio/Runtime/Sfx_Event/FinishSfxEvent.cs ================================================ using UnityEngine; using VirtueSky.Events; using VirtueSky.Inspector; namespace VirtueSky.Audio { [CreateAssetMenu(menuName = "Sunflower/Audio/Sfx Event/Finish Sfx Event", fileName = "finish_sfx_event")] [EditorIcon("scriptable_audio")] public class FinishSfxEvent : BaseEvent { } } ================================================ FILE: VirtueSky/Audio/Runtime/Sfx_Event/FinishSfxEvent.cs.meta ================================================ fileFormatVersion: 2 guid: dae25ae930684ca48408572b4079a12b MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: f6fa313956d229647ad5911f1b5d081a, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Audio/Runtime/Sfx_Event/PauseSfxEvent.cs ================================================ using UnityEngine; using VirtueSky.Events; using VirtueSky.Inspector; namespace VirtueSky.Audio { [CreateAssetMenu(menuName = "Sunflower/Audio/Sfx Event/Pause Sfx Event", fileName = "pause_sfx_event")] [EditorIcon("scriptable_audio")] public class PauseSfxEvent : BaseEvent { } } ================================================ FILE: VirtueSky/Audio/Runtime/Sfx_Event/PauseSfxEvent.cs.meta ================================================ fileFormatVersion: 2 guid: d6cf60657a4f4fe48c1e7a836cec9746 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: f6fa313956d229647ad5911f1b5d081a, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Audio/Runtime/Sfx_Event/PlaySfxEvent.cs ================================================ using UnityEngine; using VirtueSky.Events; using VirtueSky.Inspector; namespace VirtueSky.Audio { [CreateAssetMenu(menuName = "Sunflower/Audio/Sfx Event/Play Sfx Event", fileName = "play_sfx_event")] [EditorIcon("scriptable_audio")] public class PlaySfxEvent : BaseEvent { } } ================================================ FILE: VirtueSky/Audio/Runtime/Sfx_Event/PlaySfxEvent.cs.meta ================================================ fileFormatVersion: 2 guid: 797820d819bc40e585a07f1deeb9d3ce MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: f6fa313956d229647ad5911f1b5d081a, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Audio/Runtime/Sfx_Event/ResumeSfxEvent.cs ================================================ using UnityEngine; using VirtueSky.Events; using VirtueSky.Inspector; namespace VirtueSky.Audio { [CreateAssetMenu(menuName = "Sunflower/Audio/Sfx Event/Resume Sfx Event", fileName = "resume_sfx_event")] [EditorIcon("scriptable_audio")] public class ResumeSfxEvent : BaseEvent { } } ================================================ FILE: VirtueSky/Audio/Runtime/Sfx_Event/ResumeSfxEvent.cs.meta ================================================ fileFormatVersion: 2 guid: 69920a2e5b00475c8b3ef12220c0d857 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: f6fa313956d229647ad5911f1b5d081a, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Audio/Runtime/Sfx_Event/StopAllSfxEvent.cs ================================================ using UnityEngine; using VirtueSky.Events; using VirtueSky.Inspector; namespace VirtueSky.Audio { [CreateAssetMenu(menuName = "Sunflower/Audio/Sfx Event/Stop All Sfx Event", fileName = "stop_all_sfx_event")] [EditorIcon("scriptable_audio")] public class StopAllSfxEvent : EventNoParam { } } ================================================ FILE: VirtueSky/Audio/Runtime/Sfx_Event/StopAllSfxEvent.cs.meta ================================================ fileFormatVersion: 2 guid: 93775b3394ad4d82bdc5ccec6da042a8 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: f6fa313956d229647ad5911f1b5d081a, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Audio/Runtime/Sfx_Event/StopSfxEvent.cs ================================================ using UnityEngine; using VirtueSky.Events; using VirtueSky.Inspector; namespace VirtueSky.Audio { [CreateAssetMenu(menuName = "Sunflower/Audio/Sfx Event/Stop Sfx Event", fileName = "stop_sfx_event")] [EditorIcon("scriptable_audio")] public class StopSfxEvent : BaseEvent { } } ================================================ FILE: VirtueSky/Audio/Runtime/Sfx_Event/StopSfxEvent.cs.meta ================================================ fileFormatVersion: 2 guid: d6777856ee46403eb05f154212201213 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: f6fa313956d229647ad5911f1b5d081a, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Audio/Runtime/Sfx_Event.meta ================================================ fileFormatVersion: 2 guid: 9f13899b470548ada5efd57120f05db4 timeCreated: 1708586378 ================================================ FILE: VirtueSky/Audio/Runtime/SoundCache.cs ================================================ using System; namespace VirtueSky.Audio { [Serializable] public class SoundCache { internal int key; internal SoundData soundData; public SoundCache(int _key, SoundData _soundData) { key = _key; soundData = _soundData; } } } ================================================ FILE: VirtueSky/Audio/Runtime/SoundCache.cs.meta ================================================ fileFormatVersion: 2 guid: 7ed6986a4d9b4a339782b0aed0f5a2a5 timeCreated: 1715228780 ================================================ FILE: VirtueSky/Audio/Runtime/SoundComponent.cs ================================================ using System; using PrimeTween; using UnityEngine; using UnityEngine.Events; using VirtueSky.Core; using VirtueSky.Inspector; namespace VirtueSky.Audio { [RequireComponent(typeof(AudioSource))] [EditorIcon("icon_csharp")] public class SoundComponent : CacheComponent { [ReadOnly, SerializeField] private int key; public event UnityAction OnCompleted; public event UnityAction OnPaused; public event UnityAction OnResumed; public event UnityAction OnStopped; public AudioClip GetClip => component.clip; public bool IsPlaying => component.isPlaying; public bool IsLooping => component.loop; public float Volume { get => component.volume; set => component.volume = value; } public int Key { get => key; set => key = value; } private void Awake() { component.playOnAwake = false; } internal void PlayAudioClip(AudioClip audioClip, bool isLooping, float volume) { if (audioClip == null) { Debug.LogError($"AudioClip is null"); return; } component.clip = audioClip; component.loop = isLooping; component.volume = volume; component.time = 0; component.Play(); if (!isLooping) { App.Delay(this, audioClip.length, OnCompletedInvoke); } } void FadeInVolumeMusic(AudioClip audioClip, bool isLooping, float endValue, float duration) { PlayAudioClip(audioClip, isLooping, 0); Tween.AudioVolume(component, endValue, duration); } void FadeOutVolumeMusic(float duration, Action fadeCompleted) { Tween.AudioVolume(component, 0, duration).OnComplete(fadeCompleted); } internal void Resume() { OnResumed?.Invoke(this); component.UnPause(); } internal void Pause() { OnPaused?.Invoke(this); component.Pause(); } internal void Stop() { OnStopped?.Invoke(this); component.Stop(); } internal void Finish() { if (!component.loop) return; component.loop = false; float remainingTime = component.clip.length - component.time; App.Delay(this, remainingTime, OnCompletedInvoke); } internal void FadePlayMusic(AudioClip audioClip, bool isLooping, float volume, bool isMusicFadeVolume, float durationOut, float durationIn) { if (isMusicFadeVolume && volume != 0) { if (component.isPlaying) { FadeOutVolumeMusic(durationOut, () => { FadeInVolumeMusic(audioClip, isLooping, volume, durationIn); }); } else { FadeInVolumeMusic(audioClip, isLooping, volume, durationIn); } } else { PlayAudioClip(audioClip, isLooping, volume); } } private void OnCompletedInvoke() { OnCompleted?.Invoke(this); } } } ================================================ FILE: VirtueSky/Audio/Runtime/SoundComponent.cs.meta ================================================ fileFormatVersion: 2 guid: 553b54cd20a24345a93a5afbb0dea5e0 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Audio/Runtime/SoundData.cs ================================================ using System.Collections.Generic; using UnityEngine; using VirtueSky.Inspector; using VirtueSky.Core; using VirtueSky.Misc; namespace VirtueSky.Audio { [CreateAssetMenu(menuName = "Sunflower/Audio/Sound Data", fileName = "sound_data")] [EditorIcon("scriptable_audioclip")] public class SoundData : BaseSO { public enum GetType { Random, Sequence } [Space] public bool loop = false; [Range(0f, 1f)] public float volume = 1; [Header("Fade Volume - Only Music"), Tooltip("Only Music Background")] public bool isMusicFadeVolume = false; [ShowIf(nameof(isMusicFadeVolume), true)] public float fadeInDuration = .5f; [ShowIf(nameof(isMusicFadeVolume), true)] public float fadeOutDuration = .5f; [Space] public GetType getType = GetType.Random; [SerializeField] private List audioClips; private int sequenceIndex = 0; public int NumberOfAudioClips => audioClips.Count; public List AudioClips() => audioClips; public AudioClip GetAudioClip() { if (audioClips.Count > 0) { switch (getType) { case GetType.Random: return audioClips[Random.Range(0, audioClips.Count)]; case GetType.Sequence: var clip = audioClips[sequenceIndex]; if (sequenceIndex < audioClips.Count - 1) { sequenceIndex++; } else { sequenceIndex = 0; } return clip; } } return null; } public void AddAudioClip(AudioClip audioClip) { audioClips.Add(audioClip); } public void AddAudioClips(List clips) { audioClips.Adds(clips); } public void AddAudioClips(AudioClip[] clips) { audioClips.Adds(clips); } public void ClearAudioClips() { if (audioClips.IsNullOrEmpty()) return; audioClips.Clear(); } } } ================================================ FILE: VirtueSky/Audio/Runtime/SoundData.cs.meta ================================================ fileFormatVersion: 2 guid: 474a3bbd13954ce3abb782ceec59e692 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 3db558bebc410834889c3cdb93ca89b1, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Audio/Runtime/Volume_Variable/MusicVolumeChange.cs ================================================ using UnityEngine; using VirtueSky.Inspector; using VirtueSky.Variables; namespace VirtueSky.Audio { [CreateAssetMenu(menuName = "Sunflower/Audio/Volume Change Variable/Music Volume Change", fileName = "music_volume")] [EditorIcon("scriptable_variable")] public class MusicVolumeChange : FloatVariable { } } ================================================ FILE: VirtueSky/Audio/Runtime/Volume_Variable/MusicVolumeChange.cs.meta ================================================ fileFormatVersion: 2 guid: 04035b55bf6d4056848898fcc6217886 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 8f06818ab5c1c06439abc547979c8edd, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Audio/Runtime/Volume_Variable/SfxVolumeChange.cs ================================================ using UnityEngine; using VirtueSky.Inspector; using VirtueSky.Variables; namespace VirtueSky.Audio { [CreateAssetMenu(menuName = "Sunflower/Audio/Volume Change Variable/Sfx Volume Change", fileName = "sfx_volume")] [EditorIcon("scriptable_variable")] public class SfxVolumeChange : FloatVariable { } } ================================================ FILE: VirtueSky/Audio/Runtime/Volume_Variable/SfxVolumeChange.cs.meta ================================================ fileFormatVersion: 2 guid: dbff0f3c083045338776b184bac0261a MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 8f06818ab5c1c06439abc547979c8edd, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Audio/Runtime/Volume_Variable.meta ================================================ fileFormatVersion: 2 guid: 3f73d8c16cec4ccc88ce2afd329699ec timeCreated: 1708587464 ================================================ FILE: VirtueSky/Audio/Runtime/virtuesky.sunflower.audio.asmdef ================================================ { "name": "Virtuesky.Sunflower.Audio", "rootNamespace": "", "references": [ "GUID:acb3cac55c622ec459c8caadf707623a", "GUID:bd40169efe8642149b1d2b72ba4903ce", "GUID:35d694408290717499b3838802212c7f", "GUID:ce8c6e3f188ed064f933ef35b46bf8bd", "GUID:324caed91501a9c47a04ebfd87b68794", "GUID:80ecb87cae9c44d19824e70ea7229748", "GUID:c904f6d969e991d459a0843b71c22ec5", "GUID:c282fd4f3fc2c7540914e85842a013c7", "GUID:540154dd0c5ed9a4dbbe695c402232fb", "GUID:fca7ec166e04dc948b624a983315e2c9" ], "includePlatforms": [], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], "versionDefines": [], "noEngineReferences": false } ================================================ FILE: VirtueSky/Audio/Runtime/virtuesky.sunflower.audio.asmdef.meta ================================================ fileFormatVersion: 2 guid: 2ba9ab3e4292d6e4b81f0022dc854eee AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Audio/Runtime.meta ================================================ fileFormatVersion: 2 guid: 2b3ed978f9e1d42e1ab7b5ee2ed548af folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Audio.meta ================================================ fileFormatVersion: 2 guid: 4b793d0ec10139c4ebef842e4332fc00 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Button/Editor/ButtomCustomEditor.cs ================================================ using UnityEditor; using UnityEngine; using VirtueSky.UIButton; using VirtueSky.UtilsEditor; #if UNITY_EDITOR [CustomEditor(typeof(ButtonCustom), true)] [CanEditMultipleObjects] public class ButtomCustomEditor : UnityEditor.UI.ButtonEditor { private ButtonCustom _buttonCustom; private SerializedProperty _isMotion; private SerializedProperty _ease; private SerializedProperty _scale; private SerializedProperty _easingTypes; private SerializedProperty _clickButtonEvent; private SerializedProperty _isShrugOver; private SerializedProperty _timeShrug; private SerializedProperty _strength; private SerializedProperty _useSoundFx; private SerializedProperty _playSfxEvent; private SerializedProperty _soundDataClickButton; protected override void OnEnable() { base.OnEnable(); _buttonCustom = target as ButtonCustom; _isMotion = serializedObject.FindProperty("isMotion"); _easingTypes = serializedObject.FindProperty("easingTypes"); _scale = serializedObject.FindProperty("scale"); _clickButtonEvent = serializedObject.FindProperty("clickButtonEvent"); _isShrugOver = serializedObject.FindProperty("isShrugOver"); _timeShrug = serializedObject.FindProperty("timeShrug"); _strength = serializedObject.FindProperty("strength"); _useSoundFx = serializedObject.FindProperty("useSoundFx"); _playSfxEvent = serializedObject.FindProperty("playSfxEvent"); _soundDataClickButton = serializedObject.FindProperty("soundDataClickButton"); } public override void OnInspectorGUI() { base.OnInspectorGUI(); serializedObject.Update(); GUILayout.Space(5); GUILayout.Space(5); Uniform.DrawGroupFoldout("button_custom_setting", "Setting", () => DrawSetting(), true); serializedObject.ApplyModifiedProperties(); serializedObject.Update(); } void DrawSetting() { EditorGUILayout.BeginHorizontal(); EditorGUILayout.PropertyField(_clickButtonEvent); GUILayout.Space(2); if (GUILayout.Button("Create", GUILayout.Width(55))) { _buttonCustom.GetClickButtonEvent(); } EditorGUILayout.EndHorizontal(); EditorGUILayout.PropertyField(_isMotion); if (_isMotion.boolValue) { EditorGUILayout.PropertyField(_easingTypes); EditorGUILayout.PropertyField(_scale); EditorGUILayout.PropertyField(_isShrugOver); if (_isShrugOver.boolValue) { EditorGUILayout.PropertyField(_timeShrug); EditorGUILayout.PropertyField(_strength); } } GUILayout.Space(5); EditorGUILayout.PropertyField(_useSoundFx); if (_useSoundFx.boolValue) { EditorGUILayout.PropertyField(_playSfxEvent); EditorGUILayout.PropertyField(_soundDataClickButton); } } } #endif ================================================ FILE: VirtueSky/Button/Editor/ButtomCustomEditor.cs.meta ================================================ fileFormatVersion: 2 guid: dec209bc2c357084bb099281e69d88e1 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Button/Editor/Virtuesky.Sunflower.Button.Editor.asmdef ================================================ { "name": "Virtuesky.Sunflower.Button.Editor", "rootNamespace": "", "references": [ "GUID:c904f6d969e991d459a0843b71c22ec5", "GUID:18d115b3ed531e149a91cb3e69e202c5" ], "includePlatforms": [ "Editor" ], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], "versionDefines": [], "noEngineReferences": false } ================================================ FILE: VirtueSky/Button/Editor/Virtuesky.Sunflower.Button.Editor.asmdef.meta ================================================ fileFormatVersion: 2 guid: a4d70e152f59a2b4788851c89dfa3ea8 AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Button/Editor.meta ================================================ fileFormatVersion: 2 guid: 5f2fea8cee7f953469bbe7cff4d9b443 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Button/Runtime/ButtonCustom.cs ================================================ using PrimeTween; using UnityEditor; using UnityEngine; using UnityEngine.EventSystems; using VirtueSky.Audio; using VirtueSky.Inspector; using VirtueSky.Events; using VirtueSky.Misc; using VirtueSky.Utils; using Button = UnityEngine.UI.Button; #if UNITY_EDITOR using VirtueSky.UtilsEditor; #endif namespace VirtueSky.UIButton { [EditorIcon("icon_button")] public abstract class ButtonCustom : Button { public ClickButtonEvent clickButtonEvent; [HeaderLine("Motion", false, CustomColor.Yellow, CustomColor.Orange)] [SerializeField] private bool isMotion = true; [SerializeField] private Ease easingTypes = Ease.OutQuint; [SerializeField] private float scale = 0.9f; [SerializeField] private bool isShrugOver; [SerializeField] private float timeShrug = .2f; [SerializeField] private float strength = .2f; [HeaderLine("Sound Fx Click Button", false, CustomColor.Aqua, CustomColor.Salmon)] [SerializeField] private bool useSoundFx; [SerializeField] private PlaySfxEvent playSfxEvent; [SerializeField] private SoundData soundDataClickButton; Vector3 originScale = Vector3.one; private bool canShrug = true; private Tween _tween; protected override void OnEnable() { base.OnEnable(); originScale = transform.localScale; } protected override void OnDisable() { base.OnDisable(); ResetScale(); } public override void OnPointerDown(PointerEventData eventData) { base.OnPointerDown(eventData); DoScale(); if (useSoundFx) { soundDataClickButton.PlaySfx(playSfxEvent); } if (clickButtonEvent != null) { clickButtonEvent.Raise(); } else { Debug.Log($"Click button event ({gameObject.name}) null"); } } public override void OnPointerUp(PointerEventData eventData) { base.OnPointerUp(eventData); ResetScale(); } public override void OnPointerExit(PointerEventData eventData) { base.OnPointerExit(eventData); Shrug(); } void DoScale() { if (isMotion) { _tween = Tween.Scale(transform, originScale * scale, .15f, easingTypes); } } void Shrug() { if (isMotion && isShrugOver && canShrug) { canShrug = false; if (isMotion && isShrugOver) { transform.Shrug(timeShrug, strength, Ease.OutQuad, () => { canShrug = true; }); } } } void ResetScale() { if (isMotion) { _tween.Stop(); transform.localScale = originScale; } } #if UNITY_EDITOR protected override void Reset() { base.Reset(); GetClickButtonEvent(); playSfxEvent = CreateAsset.CreateAndGetScriptableAsset("/Audio/Sfx_Event", "play_sfx_event", false); } public void GetClickButtonEvent() { clickButtonEvent = CreateAsset.CreateAndGetScriptableAsset("/Event"); EditorUtility.SetDirty(this); } #endif } } ================================================ FILE: VirtueSky/Button/Runtime/ButtonCustom.cs.meta ================================================ fileFormatVersion: 2 guid: 77a8a8f178e747a4b39b894fbf66604c MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 64bffa989a83702458593189b3a27b57, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Button/Runtime/ButtonTMP.cs ================================================ using TMPro; using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.UIButton { [RequireComponent(typeof(TextMeshProUGUI))] [EditorIcon("icon_button")] public class ButtonTMP : ButtonCustom { } } ================================================ FILE: VirtueSky/Button/Runtime/ButtonTMP.cs.meta ================================================ fileFormatVersion: 2 guid: ba973a132e6c491880e5a1aae7803eea MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 64bffa989a83702458593189b3a27b57, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Button/Runtime/ButtonText.cs ================================================ using UnityEngine; using UnityEngine.UI; using VirtueSky.Inspector; namespace VirtueSky.UIButton { [RequireComponent(typeof(Text))] [EditorIcon("icon_button")] public class ButtonText : ButtonCustom { #if UNITY_EDITOR protected override void Reset() { base.Reset(); var label = GetComponent(); label.color = new Color(255, 255, 255, 255); label.text = "Button_Text"; label.fontSize = 50; label.alignment = TextAnchor.MiddleCenter; var rect = GetComponent(); rect.localScale = Vector3.one; rect.position = Vector3.zero; rect.sizeDelta = new Vector2(300, 80); } #endif } } ================================================ FILE: VirtueSky/Button/Runtime/ButtonText.cs.meta ================================================ fileFormatVersion: 2 guid: 6e5d3bd7e9f844e5ad509941360c6c44 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 64bffa989a83702458593189b3a27b57, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Button/Runtime/ButtonUI.cs ================================================ using UnityEngine; using UnityEngine.UI; using VirtueSky.Inspector; namespace VirtueSky.UIButton { [RequireComponent(typeof(Image))] [EditorIcon("icon_button")] public class ButtonUI : ButtonCustom { } } ================================================ FILE: VirtueSky/Button/Runtime/ButtonUI.cs.meta ================================================ fileFormatVersion: 2 guid: 7b68f598bc9541c7b9f48bf2b23de502 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 64bffa989a83702458593189b3a27b57, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Button/Runtime/ButtonUI_TMP.cs ================================================ using TMPro; using UnityEngine; using UnityEngine.UI; using VirtueSky.Inspector; namespace VirtueSky.UIButton { [RequireComponent(typeof(Image))] [EditorIcon("icon_button")] public class ButtonUI_TMP : ButtonCustom { #if UNITY_EDITOR protected override void Reset() { base.Reset(); var label = new GameObject("Label"); label.transform.SetParent(this.transform); var text = label.AddComponent(); text.color = new Color(0, 0, 0, 255); text.text = "Label Button"; text.horizontalAlignment = HorizontalAlignmentOptions.Center; text.verticalAlignment = VerticalAlignmentOptions.Middle; var rectTransform = label.GetComponent(); var rectTransformParent = GetComponent(); rectTransform.localScale = rectTransformParent.localScale; rectTransform.position = rectTransformParent.position; } #endif } } ================================================ FILE: VirtueSky/Button/Runtime/ButtonUI_TMP.cs.meta ================================================ fileFormatVersion: 2 guid: c66092e8fe574c688a4c6e65b36bfd41 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 64bffa989a83702458593189b3a27b57, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Button/Runtime/ButtonUI_Text.cs ================================================ using UnityEngine; using UnityEngine.UI; using VirtueSky.Inspector; namespace VirtueSky.UIButton { [RequireComponent(typeof(Image))] [EditorIcon("icon_button")] public class ButtonUI_Text : ButtonCustom { #if UNITY_EDITOR protected override void Reset() { base.Reset(); var labelObj = new GameObject("Label"); labelObj.transform.SetParent(transform); var label = labelObj.AddComponent(); label.color = new Color(0, 0, 0, 255); label.text = "Button_Text"; label.fontSize = 50; label.alignment = TextAnchor.MiddleCenter; var rect = labelObj.GetComponent(); var rectParent = GetComponent(); rect.localScale = rectParent.localScale; rect.position = rectParent.position; } #endif } } ================================================ FILE: VirtueSky/Button/Runtime/ButtonUI_Text.cs.meta ================================================ fileFormatVersion: 2 guid: 9d99d72c109e467c8853cf4074e0adc7 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 64bffa989a83702458593189b3a27b57, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Button/Runtime/Virtuesky.Sunflower.Button.asmdef ================================================ { "name": "Virtuesky.Sunflower.Button", "rootNamespace": "", "references": [ "GUID:bd40169efe8642149b1d2b72ba4903ce", "GUID:6055be8ebefd69e48b49212b09b47b2f", "GUID:acb3cac55c622ec459c8caadf707623a", "GUID:c904f6d969e991d459a0843b71c22ec5", "GUID:fca7ec166e04dc948b624a983315e2c9", "GUID:324caed91501a9c47a04ebfd87b68794", "GUID:80ecb87cae9c44d19824e70ea7229748", "GUID:c282fd4f3fc2c7540914e85842a013c7", "GUID:2ba9ab3e4292d6e4b81f0022dc854eee" ], "includePlatforms": [], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], "versionDefines": [ { "name": "com.unity.textmeshpro", "expression": "", "define": "" } ], "noEngineReferences": false } ================================================ FILE: VirtueSky/Button/Runtime/Virtuesky.Sunflower.Button.asmdef.meta ================================================ fileFormatVersion: 2 guid: 18d115b3ed531e149a91cb3e69e202c5 AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Button/Runtime.meta ================================================ fileFormatVersion: 2 guid: 38260143c92a707439a61a3aece91153 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Button.meta ================================================ fileFormatVersion: 2 guid: f826083e0d994d14ab3a31609950179e folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Component/AnimancerComponent/HandleAnimancerComponent.cs ================================================ #if VIRTUESKY_ANIMANCER using Animancer; using System; using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Component { [RequireComponent(typeof(AnimancerComponent))] [EditorIcon("icon_csharp"), HideMonoScript] public class HandleAnimancerComponent : MonoBehaviour { [SerializeField] private AnimancerComponent animancerComponent; public AnimancerComponent AnimancerComponent => animancerComponent; public bool IsPlaying(ClipTransition clip) => animancerComponent.IsPlaying(clip); public void PlayAnim(ClipTransition clip, Action _endAnim = null, float _durationFade = .2f, bool isCheckPlayingClip = true, FadeMode mode = default, object _owner = null) { if (isCheckPlayingClip) { if (!animancerComponent.IsPlaying(clip)) { Handle(); } } else { Handle(); } void Handle() { var state = animancerComponent.Play(clip, clip.Clip.length * _durationFade, mode); if (_endAnim != null) { object owner = _owner ?? animancerComponent; state.Events(owner).OnEnd += OnEndAnim; void OnEndAnim() { state.Events(owner).OnEnd -= OnEndAnim; _endAnim?.Invoke(); } } } } // Freeze a single animation on its current frame: public void PauseClip(ClipTransition clip) { animancerComponent.States[clip].IsPlaying = false; } // Freeze all animations on their current frame: public void PauseAll() { animancerComponent.Graph.PauseGraph(); } // Stop a single animation from affecting the character and rewind it to the start: public void StopClip(ClipTransition clip) { animancerComponent.Stop(clip); // Or you can call it on the state directly: var state = animancerComponent.States[clip]; state.Stop(); } // Stop all animations from affecting the character and rewind them to the start: public void StopAll() { animancerComponent.Stop(); } #if UNITY_EDITOR private void Reset() { if (animancerComponent == null) { animancerComponent = GetComponent(); } } #endif } } #endif ================================================ FILE: VirtueSky/Component/AnimancerComponent/HandleAnimancerComponent.cs.meta ================================================ fileFormatVersion: 2 guid: b50203cff2b74e849a2fe7c6bb333776 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Component/AnimancerComponent.meta ================================================ fileFormatVersion: 2 guid: 5feb8e7c264a6744baac771c57a700af folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Component/BounceComponent.cs ================================================ using UnityEngine; using VirtueSky.Core; using VirtueSky.Inspector; namespace VirtueSky.Component { [EditorIcon("icon_csharp"), HideMonoScript] public class BounceComponent : BaseMono { [Header("Attributes")] public bool isRotate = false; public float degreesPerSecond = 15.0f; public float amplitude = 5f; public float frequency = 1f; private Vector3 _posOffset; private Vector3 _tempPos; private bool isBounce = true; public override void OnEnable() { base.OnEnable(); isBounce = true; _posOffset = transform.localPosition; } public void Pause() { isBounce = false; } public void Resume() { isBounce = true; } public override void FixedTick() { base.FixedTick(); if (isBounce) { if (isRotate) { transform.Rotate(new Vector3(0f, Time.deltaTime * degreesPerSecond, 0f), Space.World); } _tempPos = _posOffset; _tempPos.y += Mathf.Sin(Time.fixedTime * Mathf.PI * frequency) * amplitude; transform.localPosition = _tempPos; } } } } ================================================ FILE: VirtueSky/Component/BounceComponent.cs.meta ================================================ fileFormatVersion: 2 guid: 3738ba9d850a44feadde2a3c37c3df41 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Component/Buoyancy2DComponent.cs ================================================ using UnityEngine; using VirtueSky.Core; using VirtueSky.Inspector; namespace VirtueSky.Component { [RequireComponent(typeof(Rigidbody2D))] [EditorIcon("icon_csharp"), HideMonoScript] public class Buoyancy2DComponent : CacheComponent { public Transform[] floaters; public float underWaterDrag = 3f; public float underWaterAngularDrag = 1f; public float airDrag = 0f; public float airAngularDrag = 0.05f; public float floatingPower = 15f; public float waterHeight = 0f; bool Underwater; int floatersUnderWater; // Update is called once per frame public override void FixedTick() { base.FixedTick(); floatersUnderWater = 0; for (int i = 0; i < floaters.Length; i++) { float diff = floaters[i].position.y - waterHeight; if (diff < 0) { component.AddForceAtPosition(Vector3.up * floatingPower * Mathf.Abs(diff), floaters[i].position, ForceMode2D.Force); floatersUnderWater += 1; if (!Underwater) { Underwater = true; SwitchState(true); } } } if (Underwater && floatersUnderWater == 0) { Underwater = false; SwitchState(false); } } void SwitchState(bool isUnderwater) { #if UNITY_6000_0_OR_NEWER component.linearDamping = isUnderwater ? underWaterDrag : airDrag; component.angularDamping = isUnderwater ? underWaterAngularDrag : airAngularDrag; #else component.drag = isUnderwater ? underWaterDrag : airDrag; component.angularDrag = isUnderwater ? underWaterAngularDrag : airAngularDrag; #endif } } } ================================================ FILE: VirtueSky/Component/Buoyancy2DComponent.cs.meta ================================================ fileFormatVersion: 2 guid: 633b7fa9831f4185b49828dffeb5ae0d MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Component/BuoyancyComponent.cs ================================================ using UnityEngine; using VirtueSky.Core; using VirtueSky.Inspector; namespace VirtueSky.Component { [RequireComponent(typeof(Rigidbody))] [EditorIcon("icon_csharp"), HideMonoScript] public class BuoyancyComponent : CacheComponent { public Transform[] floaters; public float underWaterDrag = 3f; public float underWaterAngularDrag = 1f; public float airDrag = 0f; public float airAngularDrag = 0.05f; public float floatingPower = 15f; public float waterHeight = 0f; bool Underwater; int floatersUnderWater; // Update is called once per frame public override void FixedTick() { base.FixedTick(); floatersUnderWater = 0; for (int i = 0; i < floaters.Length; i++) { float diff = floaters[i].position.y - waterHeight; if (diff < 0) { component.AddForceAtPosition(Vector3.up * floatingPower * Mathf.Abs(diff), floaters[i].position, ForceMode.Force); floatersUnderWater += 1; if (!Underwater) { Underwater = true; SwitchState(true); } } } if (Underwater && floatersUnderWater == 0) { Underwater = false; SwitchState(false); } } void SwitchState(bool isUnderwater) { #if UNITY_6000_0_OR_NEWER component.linearDamping = isUnderwater ? underWaterDrag : airDrag; component.angularDamping = isUnderwater ? underWaterAngularDrag : airAngularDrag; #else component.drag = isUnderwater ? underWaterDrag : airDrag; component.angularDrag = isUnderwater ? underWaterAngularDrag : airAngularDrag; #endif } } } ================================================ FILE: VirtueSky/Component/BuoyancyComponent.cs.meta ================================================ fileFormatVersion: 2 guid: 638f3f3b2ea44398921d0a90743d5882 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Component/EffectAppearComponent.cs ================================================ using UnityEngine; using PrimeTween; using VirtueSky.Core; using VirtueSky.Inspector; namespace VirtueSky.Component { [EditorIcon("icon_csharp"), HideMonoScript] public class EffectAppearComponent : BaseMono { public float delay = 0.1f; [Range(0, 2f)] public float TimeScale = .7f; public Ease ease = Ease.OutBack; public Vector3 fromScale = new Vector3(.5f, .5f, .5f); private Vector3 CurrentScale; private Tween _tween; public void Awake() { CurrentScale = transform.localScale; } public void OnEnable() { transform.localScale = fromScale; App.Delay(this, delay, DoEffect); } public void DoEffect() { if (!gameObject.activeInHierarchy) return; _tween = Tween.Scale(transform, CurrentScale, TimeScale, ease).OnComplete(() => { _tween.Stop(); }, false); } public override void OnDisable() { base.OnDisable(); _tween.Stop(); } } } ================================================ FILE: VirtueSky/Component/EffectAppearComponent.cs.meta ================================================ fileFormatVersion: 2 guid: 8d6d71043917f4558833eb085b54db75 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Component/EffectZoomInOutComponent.cs ================================================ using PrimeTween; using UnityEngine; using VirtueSky.Core; using VirtueSky.Inspector; namespace VirtueSky.Component { [EditorIcon("icon_csharp"), HideMonoScript] public class EffectZoomInOutComponent : BaseMono { public bool playOnAwake = true; [Range(0, 2f)] public float timeDelay; [Range(0, 2f)] public float offsetScale = .1f; [Range(0, 2f)] public float timeScale = .7f; public Ease ease = Ease.Linear; private Vector3 currentScale; private Tween tween; private bool isBreak = false; public void Awake() { currentScale = transform.localScale; } public void OnEnable() { if (playOnAwake) { Play(); } } private void OnDisable() { tween.Stop(); } public void Stop() { isBreak = true; tween.Stop(); } public void Play() { isBreak = false; DoEffect(offsetScale, false); } public void DoEffect(float offsetScale, bool delay) { if (!gameObject.activeInHierarchy) return; if (isBreak) return; App.Delay(this, timeDelay * (delay ? 1 : 0), () => { tween = transform.Scale( new Vector3(currentScale.x + offsetScale, currentScale.y + offsetScale, currentScale.z + offsetScale), timeScale, ease) .OnComplete(() => { DoEffect(-offsetScale, !delay); }, false); }); } } } ================================================ FILE: VirtueSky/Component/EffectZoomInOutComponent.cs.meta ================================================ fileFormatVersion: 2 guid: 3ade0ecb53764967a07ba5247a582386 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Component/FollowTargetComponent.cs ================================================ using UnityEngine; using VirtueSky.Core; using VirtueSky.Inspector; using VirtueSky.Misc; namespace VirtueSky.Component { [EditorIcon("icon_csharp"), HideMonoScript] public class FollowTargetComponent : BaseMono { [Tooltip("if currentTrans is null, then currentTrans will be set up with the current game object"), SerializeField] private Transform currentTrans; [Space, SerializeField] private Transform targetTrans; [SerializeField] private bool useOffsetTrans = true; [ShowIf(nameof(useOffsetTrans), true), ReadOnly, SerializeField] private Vector3 offsetTrans; [Space, SerializeField] private DirectionFollowTarget directionFollowTarget; [Space, SerializeField] private TypeFollowTarget typeFollowTarget; [Tooltip("Value used to interpolate between target and this object"), ShowIf(nameof(typeFollowTarget), TypeFollowTarget.Lerp), SerializeField] private float interpolateValue = 0.05f; [Tooltip("The current velocity, this value is modified by the function every time you call it."), ShowIf(nameof(typeFollowTarget), TypeFollowTarget.SmoothDamp), SerializeField] private Vector3 currentVelocity = Vector3.zero; [Tooltip( "Approximately the time it will take to reach the target. A smaller value will reach the target faster."), ShowIf(nameof(typeFollowTarget), TypeFollowTarget.SmoothDamp), SerializeField] private float smoothTime = 0.05f; [Tooltip("Optionally allows you to clamp the maximum speed."), ShowIf(nameof(typeFollowTarget), TypeFollowTarget.SmoothDamp), SerializeField] private float maxSpeed = Mathf.Infinity; public Transform TargetTransform { get => targetTrans; set => targetTrans = value; } public Vector3 OffsetTrans { get => offsetTrans; set => offsetTrans = value; } public DirectionFollowTarget DirectionFollowTarget { get => directionFollowTarget; set => directionFollowTarget = value; } public TypeFollowTarget TypeFollowTarget { get => typeFollowTarget; set => typeFollowTarget = value; } public float InterpolateValue { get => interpolateValue; set => interpolateValue = value; } public Vector3 CurrentVelocity { get => currentVelocity; set => currentVelocity = value; } public float SmoothTime { get => smoothTime; set => smoothTime = value; } public float MaxSpeed { get => maxSpeed; set => maxSpeed = value; } private void Awake() { if (currentTrans == null) { currentTrans = gameObject.transform; } offsetTrans = useOffsetTrans ? currentTrans.position - targetTrans.position : Vector3.zero; } public void SetTarget(Transform t) { targetTrans = t; } public void SetDirectionFollowTarget(DirectionFollowTarget d) { directionFollowTarget = d; } public void SetTypeFollowTarget(TypeFollowTarget t) { typeFollowTarget = t; } public override void LateTick() { base.LateTick(); switch (typeFollowTarget) { case TypeFollowTarget.SetPosition: HandleSetPos(); break; case TypeFollowTarget.Lerp: HandleLerp(); break; case TypeFollowTarget.SmoothDamp: HandleSmoothDamp(); break; } } private void HandleSetPos() { Vector3 targetPos = targetTrans.position + offsetTrans; switch (directionFollowTarget) { case DirectionFollowTarget.XYZ: currentTrans.SetPosition(targetPos); break; case DirectionFollowTarget.XY: currentTrans.SetPositionXY(targetPos); break; case DirectionFollowTarget.XZ: currentTrans.SetPositionXZ(targetPos); break; case DirectionFollowTarget.YZ: currentTrans.SetPositionYZ(targetPos); break; case DirectionFollowTarget.X: currentTrans.SetPositionX(targetPos.x); break; case DirectionFollowTarget.Y: currentTrans.SetPositionY(targetPos.y); break; case DirectionFollowTarget.Z: currentTrans.SetPositionZ(targetPos.y); break; } } private void HandleLerp() { Vector3 interpolateVector3 = Vector3.Lerp(currentTrans.position, targetTrans.position + offsetTrans, interpolateValue); switch (directionFollowTarget) { case DirectionFollowTarget.XYZ: currentTrans.SetPosition(interpolateVector3); break; case DirectionFollowTarget.XY: currentTrans.SetPositionXY(interpolateVector3); break; case DirectionFollowTarget.XZ: currentTrans.SetPositionXZ(interpolateVector3); break; case DirectionFollowTarget.YZ: currentTrans.SetPositionYZ(interpolateVector3); break; case DirectionFollowTarget.X: currentTrans.SetPositionX(interpolateVector3.x); break; case DirectionFollowTarget.Y: currentTrans.SetPositionY(interpolateVector3.y); break; case DirectionFollowTarget.Z: currentTrans.SetPositionZ(interpolateVector3.z); break; } } private void HandleSmoothDamp() { Vector3 smoothDampVector3 = Vector3.SmoothDamp(currentTrans.position, targetTrans.position + offsetTrans, ref currentVelocity, smoothTime, maxSpeed); switch (directionFollowTarget) { case DirectionFollowTarget.XYZ: currentTrans.SetPosition(smoothDampVector3); break; case DirectionFollowTarget.XY: currentTrans.SetPositionXY(smoothDampVector3); break; case DirectionFollowTarget.XZ: currentTrans.SetPositionXZ(smoothDampVector3); break; case DirectionFollowTarget.YZ: currentTrans.SetPositionYZ(smoothDampVector3); break; case DirectionFollowTarget.X: currentTrans.SetPositionX(smoothDampVector3.x); break; case DirectionFollowTarget.Y: currentTrans.SetPositionY(smoothDampVector3.y); break; case DirectionFollowTarget.Z: currentTrans.SetPositionZ(smoothDampVector3.z); break; } } } public enum DirectionFollowTarget { XYZ, XY, XZ, YZ, X, Y, Z } public enum TypeFollowTarget { SetPosition, Lerp, SmoothDamp } } ================================================ FILE: VirtueSky/Component/FollowTargetComponent.cs.meta ================================================ fileFormatVersion: 2 guid: 1822db19afe741b39a1a8aaf05bb65fa MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Component/MoveComponent.cs ================================================ using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; using VirtueSky.Core; using VirtueSky.Inspector; namespace VirtueSky.Component { [EditorIcon("icon_csharp"), HideMonoScript] public class MoveComponent : BaseMono { public GameObject movingObject; public List points; // List of points the object will move through public float speed = 1.0f; // The speed at which the object will move between points public bool moveOnAwake = true; // Flag to indicate whether the object should start moving on awake public bool loop = true; // Flag to indicate whether the object should loop through the points private bool _reverse; // Flag to indicate whether the object should move in reverse private int _currentPoint; // The current point the object is moving towards private bool _isMoving = true; // Flag to indicate whether the object is currently moving public UnityEvent onPointReached; // Unity event to notify when a point is reached void Start() { movingObject.transform.position = points[0].position; if (!moveOnAwake) { _isMoving = false; } } public override void Tick() { base.Tick(); if (_isMoving) { if (_currentPoint < points.Count) { // Move the object towards the next point movingObject.transform.position = Vector3.MoveTowards(movingObject.transform.position, points[_currentPoint].position, speed * Time.deltaTime); if (movingObject.transform.position == points[_currentPoint].position) { // When the object reaches the point, move on to the next one onPointReached?.Invoke(_currentPoint); if (!_reverse) { _currentPoint++; } else { _currentPoint--; } if (_currentPoint == points.Count && loop) { _currentPoint = 0; } if (_currentPoint < 0 && loop) { _currentPoint = points.Count - 1; } } } } } public void StopMoving() { _isMoving = false; } public void ResumeMoving() { _isMoving = true; } public void ReverseMoving() { _reverse = !_reverse; if (_currentPoint == 0) { _currentPoint = points.Count - 1; } else if (_currentPoint == points.Count - 1) { _currentPoint = 0; } } } } ================================================ FILE: VirtueSky/Component/MoveComponent.cs.meta ================================================ fileFormatVersion: 2 guid: 46e435ee81f643968c015f2e2c597987 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Component/ResizeCameraOrthographicComponent.cs ================================================ using UnityEngine; using VirtueSky.Core; using VirtueSky.Inspector; namespace VirtueSky.Component { [EditorIcon("icon_csharp"), HideMonoScript] public class ResizeCameraOrthographicComponent : CacheComponent { [SerializeField] private Vector2 ratio = new Vector2(9, 16); protected override void Awake() { base.Awake(); float sizeStart = component.orthographicSize; float size = component.orthographicSize * ratio.x / (ratio.y * component.aspect); if (size > sizeStart) component.orthographicSize = size; } } } ================================================ FILE: VirtueSky/Component/ResizeCameraOrthographicComponent.cs.meta ================================================ fileFormatVersion: 2 guid: 4d0482e28b214f308276639a11ee7036 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Component/ResizeMatchCanvasScalerComponent.cs ================================================ using UnityEngine; using UnityEngine.UI; using VirtueSky.Core; using VirtueSky.Inspector; namespace VirtueSky.Component { [EditorIcon("icon_csharp"), HideMonoScript] public class ResizeMatchCanvasScalerComponent : CacheComponent { [SerializeField, Range(0, 1)] private float aspectRatio = 0.6f; [SerializeField] private Canvas canvas; [SerializeField, ReadOnly] private Camera camera; protected override void Awake() { base.Awake(); GetCanvas(); if (camera != null) { component.matchWidthOrHeight = camera.aspect > aspectRatio ? 1 : 0; } } void GetCanvas() { if (canvas == null) { canvas = GetComponent(); if (canvas.worldCamera) { camera = canvas.worldCamera; } } } #if UNITY_EDITOR protected override void Reset() { base.Reset(); GetCanvas(); } #endif } } ================================================ FILE: VirtueSky/Component/ResizeMatchCanvasScalerComponent.cs.meta ================================================ fileFormatVersion: 2 guid: bdbb49ade0bd47989ddd583f82a20a8a MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Component/RotateComponent.cs ================================================ using UnityEditor; using UnityEngine; using VirtueSky.Core; using VirtueSky.Inspector; namespace VirtueSky.Component { [EditorIcon("icon_csharp"), HideMonoScript] public class RotateComponent : BaseMono { [Header("Attributes")] public bool ignoreTimeScale; public float speed = 1f; public bool rotateX; public bool rotateY; public bool rotateZ; public bool isReverse; private bool isRotate = true; public void Resume() { isRotate = true; } public void Pause() { isRotate = false; } public override void FixedTick() { base.FixedTick(); if (isRotate) { var transformTemp = transform; if (rotateX) { if (!isReverse) { transform.RotateAround(transform.position, transform.right, Time.deltaTime * 90f * speed); } else { transform.RotateAround(transform.position, transform.right, Time.deltaTime * 90f * -speed); } } if (rotateY) { if (!isReverse) { transform.RotateAround(transform.position, transform.up, Time.deltaTime * 90f * speed); } else { transform.RotateAround(transform.position, transform.up, Time.deltaTime * 90f * -speed); } } if (rotateZ) { if (!isReverse) { transform.RotateAround(transform.position, transform.forward, Time.deltaTime * 90f * speed * 1); } else { transform.RotateAround(transform.position, transform.forward, Time.deltaTime * 90f * speed * -1); } } } } } } ================================================ FILE: VirtueSky/Component/RotateComponent.cs.meta ================================================ fileFormatVersion: 2 guid: 21b97e3cc6124c14912dd93f240fe259 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Component/SafeAreaComponent.cs ================================================ using UnityEngine; using VirtueSky.Core; using VirtueSky.Inspector; namespace VirtueSky.Component { /// /// Safe area implementation for notched mobile devices. Usage: /// (1) Add this component to the top level of any GUI panel. /// (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. /// This will allow the background image to stretch to the full extents of the screen behind the notch, which looks nicer. /// (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. /// [HideMonoScript] [EditorIcon("icon_csharp")] public class SafeAreaComponent : BaseMono { #region Simulations /// /// Simulation device that uses safe area due to a physical notch or software home bar. For use in Editor only. /// public enum SimDevice { /// /// Don't use a simulated safe area - GUI will be full screen as normal. /// None, /// /// Simulate the iPhone X and Xs (identical safe areas). /// iPhoneX, /// /// Simulate the iPhone Xs Max and XR (identical safe areas). /// iPhoneXsMax, /// /// Simulate the Google Pixel 3 XL using landscape left. /// Pixel3XL_LSL, /// /// Simulate the Google Pixel 3 XL using landscape right. /// Pixel3XL_LSR } /// /// Simulation mode for use in editor only. This can be edited at runtime to toggle between different safe areas. /// public static SimDevice Sim = SimDevice.None; /// /// Normalised safe areas for iPhone X with Home indicator (ratios are identical to Xs, 11 Pro). Absolute values: /// PortraitU x=0, y=102, w=1125, h=2202 on full extents w=1125, h=2436; /// PortraitD x=0, y=102, w=1125, h=2202 on full extents w=1125, h=2436 (not supported, remains in Portrait Up); /// LandscapeL x=132, y=63, w=2172, h=1062 on full extents w=2436, h=1125; /// LandscapeR x=132, y=63, w=2172, h=1062 on full extents w=2436, h=1125. /// Aspect Ratio: ~19.5:9. /// Rect[] NSA_iPhoneX = new Rect[] { new Rect(0f, 102f / 2436f, 1f, 2202f / 2436f), // Portrait new Rect(132f / 2436f, 63f / 1125f, 2172f / 2436f, 1062f / 1125f) // Landscape }; /// /// Normalised safe areas for iPhone Xs Max with Home indicator (ratios are identical to XR, 11, 11 Pro Max). Absolute values: /// PortraitU x=0, y=102, w=1242, h=2454 on full extents w=1242, h=2688; /// PortraitD x=0, y=102, w=1242, h=2454 on full extents w=1242, h=2688 (not supported, remains in Portrait Up); /// LandscapeL x=132, y=63, w=2424, h=1179 on full extents w=2688, h=1242; /// LandscapeR x=132, y=63, w=2424, h=1179 on full extents w=2688, h=1242. /// Aspect Ratio: ~19.5:9. /// Rect[] NSA_iPhoneXsMax = new Rect[] { new Rect(0f, 102f / 2688f, 1f, 2454f / 2688f), // Portrait new Rect(132f / 2688f, 63f / 1242f, 2424f / 2688f, 1179f / 1242f) // Landscape }; /// /// Normalised safe areas for Pixel 3 XL using landscape left. Absolute values: /// PortraitU x=0, y=0, w=1440, h=2789 on full extents w=1440, h=2960; /// PortraitD x=0, y=0, w=1440, h=2789 on full extents w=1440, h=2960; /// LandscapeL x=171, y=0, w=2789, h=1440 on full extents w=2960, h=1440; /// LandscapeR x=0, y=0, w=2789, h=1440 on full extents w=2960, h=1440. /// Aspect Ratio: 18.5:9. /// Rect[] NSA_Pixel3XL_LSL = new Rect[] { new Rect(0f, 0f, 1f, 2789f / 2960f), // Portrait new Rect(0f, 0f, 2789f / 2960f, 1f) // Landscape }; /// /// Normalised safe areas for Pixel 3 XL using landscape right. Absolute values and aspect ratio same as above. /// Rect[] NSA_Pixel3XL_LSR = new Rect[] { new Rect(0f, 0f, 1f, 2789f / 2960f), // Portrait new Rect(171f / 2960f, 0f, 2789f / 2960f, 1f) // Landscape }; #endregion RectTransform Panel; Rect LastSafeArea = new Rect(0, 0, 0, 0); Vector2Int LastScreenSize = new Vector2Int(0, 0); ScreenOrientation LastOrientation = ScreenOrientation.AutoRotation; [SerializeField] bool ConformX = true; // Conform to screen safe area on X-axis (default true, disable to ignore) [SerializeField] bool ConformY = true; // Conform to screen safe area on Y-axis (default true, disable to ignore) [SerializeField] bool Logging = false; // Conform to screen safe area on Y-axis (default true, disable to ignore) void Awake() { Panel = GetComponent(); if (Panel == null) { Debug.LogError("Cannot apply safe area - no RectTransform found on " + name); Destroy(gameObject); } Refresh(); } public override void Tick() { base.Tick(); Refresh(); } void Refresh() { Rect safeArea = GetSafeArea(); if (safeArea != LastSafeArea || Screen.width != LastScreenSize.x || Screen.height != LastScreenSize.y || Screen.orientation != LastOrientation) { // Fix for having auto-rotate off and manually forcing a screen orientation. // See https://forum.unity.com/threads/569236/#post-4473253 and https://forum.unity.com/threads/569236/page-2#post-5166467 LastScreenSize.x = Screen.width; LastScreenSize.y = Screen.height; LastOrientation = Screen.orientation; ApplySafeArea(safeArea); } } Rect GetSafeArea() { Rect safeArea = Screen.safeArea; if (Application.isEditor && Sim != SimDevice.None) { Rect nsa = new Rect(0, 0, Screen.width, Screen.height); switch (Sim) { case SimDevice.iPhoneX: if (Screen.height > Screen.width) // Portrait nsa = NSA_iPhoneX[0]; else // Landscape nsa = NSA_iPhoneX[1]; break; case SimDevice.iPhoneXsMax: if (Screen.height > Screen.width) // Portrait nsa = NSA_iPhoneXsMax[0]; else // Landscape nsa = NSA_iPhoneXsMax[1]; break; case SimDevice.Pixel3XL_LSL: if (Screen.height > Screen.width) // Portrait nsa = NSA_Pixel3XL_LSL[0]; else // Landscape nsa = NSA_Pixel3XL_LSL[1]; break; case SimDevice.Pixel3XL_LSR: if (Screen.height > Screen.width) // Portrait nsa = NSA_Pixel3XL_LSR[0]; else // Landscape nsa = NSA_Pixel3XL_LSR[1]; break; default: break; } safeArea = new Rect(Screen.width * nsa.x, Screen.height * nsa.y, Screen.width * nsa.width, Screen.height * nsa.height); } return safeArea; } void ApplySafeArea(Rect r) { LastSafeArea = r; // Ignore x-axis? if (!ConformX) { r.x = 0; r.width = Screen.width; } // Ignore y-axis? if (!ConformY) { r.y = 0; r.height = Screen.height; } // Check for invalid screen startup state on some Samsung devices (see below) if (Screen.width > 0 && Screen.height > 0) { // Convert safe area rectangle from absolute pixels to normalised anchor coordinates Vector2 anchorMin = r.position; Vector2 anchorMax = r.position + r.size; anchorMin.x /= Screen.width; anchorMin.y /= Screen.height; anchorMax.x /= Screen.width; anchorMax.y /= Screen.height; // Fix for some Samsung devices (e.g. Note 10+, A71, S20) where Refresh gets called twice and the first time returns NaN anchor coordinates // See https://forum.unity.com/threads/569236/page-2#post-6199352 if (anchorMin.x >= 0 && anchorMin.y >= 0 && anchorMax.x >= 0 && anchorMax.y >= 0) { Panel.anchorMin = anchorMin; Panel.anchorMax = anchorMax; } } if (Logging) { Debug.LogFormat("New safe area applied to {0}: x={1}, y={2}, w={3}, h={4} on full extents w={5}, h={6}", name, r.x, r.y, r.width, r.height, Screen.width, Screen.height); } } } } ================================================ FILE: VirtueSky/Component/SafeAreaComponent.cs.meta ================================================ fileFormatVersion: 2 guid: 09edf4ad864147a9bd2de10bb1a5c654 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Component/SkeletonComponent/AnimationSkeleton/AnimationSkeleton.cs ================================================ #if VIRTUESKY_SKELETON using System; using System.Collections.Generic; using UnityEngine; using Spine; using Spine.Unity; using AnimationState = Spine.AnimationState; namespace VirtueSky.Component { public abstract class AnimationSkeleton : MonoBehaviour { protected Skeleton skeleton; protected AnimationState animationState; protected string animationName; public Skeleton Skeleton => skeleton; public AnimationState AnimationState => animationState; public string AnimationName => animationName; protected Dictionary cacheEvent = new Dictionary(); public virtual void Init() { animationState.Event += HandleAnimationStateEvent; } public abstract void Initialize(bool reload = false); public abstract void ChangeAnimationName(string animationName); public abstract void FlipX(bool isFlipX = false); public abstract void FlipY(bool isFlipY = false); public abstract void ChangeDataAsset(SkeletonDataAsset dataAsset); public void AddAnimation(int trackIndex, string animationName, bool loop, float timeDelay = 0) { animationState.AddAnimation(trackIndex, animationName, loop, timeDelay); } public TrackEntry PlayAnimation(int trackIndex, string animationName, bool loop = false, float speed = 1) { this.animationName = animationName; animationState.TimeScale = speed; var trackEntry = animationState.SetAnimation(trackIndex, animationName, loop); animationState.Apply(skeleton); return trackEntry; } public void RegisterEvent(string eventName, Action actionEvent = null) { if (cacheEvent.ContainsKey(eventName)) { cacheEvent[eventName] = actionEvent; } else { cacheEvent.Add(eventName, actionEvent); } } public void StopAnimation() { animationState.TimeScale = 0; } protected void HandleAnimationStateEvent(TrackEntry trackEntry, Spine.Event e) { Action action = null; if (cacheEvent.TryGetValue(e.Data.Name, out action)) { action?.Invoke(); } } } } #endif ================================================ FILE: VirtueSky/Component/SkeletonComponent/AnimationSkeleton/AnimationSkeleton.cs.meta ================================================ fileFormatVersion: 2 guid: adb2ca79f8f64dceaa0f39d965cf5d6d timeCreated: 1708057049 ================================================ FILE: VirtueSky/Component/SkeletonComponent/AnimationSkeleton/AnimationSkeletonComponent.cs ================================================ #if VIRTUESKY_SKELETON using Spine.Unity; using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Component { [RequireComponent(typeof(SkeletonAnimation))] [EditorIcon("icon_csharp"), HideMonoScript] public class AnimationSkeletonComponent : AnimationSkeleton { [SerializeField] SkeletonAnimation skeletonAnimation; public SkeletonAnimation SkeletonAnimation => skeletonAnimation; public override void Init() { skeleton = skeletonAnimation.Skeleton; animationState = skeletonAnimation.AnimationState; base.Init(); } public override void Initialize(bool reload = false) { skeletonAnimation.Initialize(reload); } public override void ChangeAnimationName(string animationName) { skeletonAnimation.AnimationName = animationName; } public override void FlipX(bool isFlipX = false) { skeletonAnimation.initialFlipX = isFlipX; } public override void FlipY(bool isFlipY = false) { skeletonAnimation.initialFlipY = isFlipY; } public override void ChangeDataAsset(SkeletonDataAsset dataAsset) { skeletonAnimation.skeletonDataAsset = dataAsset; } #if UNITY_EDITOR private void Reset() { if (skeletonAnimation == null) { skeletonAnimation = GetComponent(); } } #endif } } #endif ================================================ FILE: VirtueSky/Component/SkeletonComponent/AnimationSkeleton/AnimationSkeletonComponent.cs.meta ================================================ fileFormatVersion: 2 guid: 72d87d7da8ad434aba0a028f7a110682 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Component/SkeletonComponent/AnimationSkeleton/AnimationSkeletonUIComponent.cs ================================================ #if VIRTUESKY_SKELETON using Spine.Unity; using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Component { [RequireComponent(typeof(SkeletonGraphic))] [EditorIcon("icon_csharp"), HideMonoScript] public class AnimationSkeletonUIComponent : AnimationSkeleton { [SerializeField] SkeletonGraphic skeletonGraphic; public SkeletonGraphic SkeletonGraphic => skeletonGraphic; public override void Init() { skeleton = skeletonGraphic.Skeleton; animationState = skeletonGraphic.AnimationState; base.Init(); } public override void Initialize(bool reload = false) { skeletonGraphic.Initialize(reload); } public override void ChangeAnimationName(string animationName) { skeletonGraphic.startingAnimation = animationName; } public override void FlipX(bool isFlipX = false) { skeletonGraphic.initialFlipX = isFlipX; } public override void FlipY(bool isFlipY = false) { skeletonGraphic.initialFlipY = isFlipY; } public override void ChangeDataAsset(SkeletonDataAsset dataAsset) { skeletonGraphic.skeletonDataAsset = dataAsset; } #if UNITY_EDITOR private void Reset() { if (skeletonGraphic == null) { skeletonGraphic = GetComponent(); } } #endif } } #endif ================================================ FILE: VirtueSky/Component/SkeletonComponent/AnimationSkeleton/AnimationSkeletonUIComponent.cs.meta ================================================ fileFormatVersion: 2 guid: 9b460082b10946a1b933bf18b723251d MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Component/SkeletonComponent/AnimationSkeleton.meta ================================================ fileFormatVersion: 2 guid: e11352e7a4fed8a47986e9dd820ea474 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Component/SkeletonComponent/SkinSkeleton/SkinSkeleton.cs ================================================ #if VIRTUESKY_SKELETON using System.Collections.Generic; using Spine; using UnityEngine; using AnimationState = Spine.AnimationState; namespace VirtueSky.Component { public abstract class SkinSkeleton : MonoBehaviour { protected Skeleton skeleton; protected Spine.AnimationState animationState; public Skeleton Skeleton => skeleton; public AnimationState AnimationState => animationState; public abstract void Init(); public virtual void MixSkin(string mixSkinName) { if (skeleton == null) return; if (string.IsNullOrEmpty(mixSkinName) || mixSkinName.Equals("default")) return; skeleton.Skin.AddSkin(skeleton.Data.FindSkin(mixSkinName)); skeleton.SetSlotsToSetupPose(); animationState.Apply(skeleton); } public virtual void MixSkin(List listMixSkinName) { if (skeleton == null) return; foreach (var skinMixName in listMixSkinName) { if (!string.IsNullOrEmpty(skinMixName) && !skinMixName.Equals("default")) { skeleton.Skin.AddSkin(skeleton.Data.FindSkin(skinMixName)); } } skeleton.SetSlotsToSetupPose(); animationState.Apply(skeleton); } public virtual void MixNewSkin(string mixSkinName) { if (skeleton == null) return; if (string.IsNullOrEmpty(mixSkinName) || mixSkinName.Equals("default")) return; var mixAndMatchSkin = new Skin("temp"); mixAndMatchSkin.AddSkin(skeleton.Data.FindSkin(mixSkinName)); skeleton.SetSkin(mixAndMatchSkin); skeleton.SetSlotsToSetupPose(); animationState.Apply(skeleton); } public virtual void MixNewSkin(List listMixSkinName) { if (skeleton == null) return; var mixAndMatchSkin = new Skin("temp"); foreach (var skinMixName in listMixSkinName) { if (!string.IsNullOrEmpty(skinMixName) && !skinMixName.Equals("default")) { mixAndMatchSkin.AddSkin(skeleton.Data.FindSkin(skinMixName)); } } skeleton.SetSkin(mixAndMatchSkin); skeleton.SetSlotsToSetupPose(); animationState.Apply(skeleton); } public virtual void SetSkin(string skinName) { if (skeleton == null) return; Skin newSkin = new Skin("skin"); newSkin.AddSkin(skeleton.Data.FindSkin(skinName)); skeleton.SetSkin(newSkin); skeleton.SetSlotsToSetupPose(); animationState.Apply(skeleton); } } } #endif ================================================ FILE: VirtueSky/Component/SkeletonComponent/SkinSkeleton/SkinSkeleton.cs.meta ================================================ fileFormatVersion: 2 guid: df6ec86372015434fbefc86e083ad0a3 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Component/SkeletonComponent/SkinSkeleton/SkinSkeletonComponent.cs ================================================ #if VIRTUESKY_SKELETON using Spine.Unity; using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Component { [RequireComponent(typeof(SkeletonAnimation))] [EditorIcon("icon_csharp"), HideMonoScript] public class SkinSkeletonComponent : SkinSkeleton { [SerializeField] private SkeletonAnimation skeletonAnimation; public SkeletonAnimation SkeletonAnimation => skeletonAnimation; public override void Init() { skeleton = skeletonAnimation.Skeleton; animationState = skeletonAnimation.AnimationState; } #if UNITY_EDITOR private void Reset() { if (skeletonAnimation == null) { skeletonAnimation = GetComponent(); } } #endif } } #endif ================================================ FILE: VirtueSky/Component/SkeletonComponent/SkinSkeleton/SkinSkeletonComponent.cs.meta ================================================ fileFormatVersion: 2 guid: 7cc89fd779894fa4abbd3a16effefe80 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Component/SkeletonComponent/SkinSkeleton/SkinSkeletonUIComponent.cs ================================================ #if VIRTUESKY_SKELETON using System; using Spine.Unity; using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Component { [RequireComponent(typeof(SkeletonGraphic))] [EditorIcon("icon_csharp"), HideMonoScript] public class SkinSkeletonUIComponent : SkinSkeleton { [SerializeField] private SkeletonGraphic skeletonGraphic; public override void Init() { skeleton = skeletonGraphic.Skeleton; animationState = skeletonGraphic.AnimationState; } #if UNITY_EDITOR private void Reset() { if (skeletonGraphic == null) { skeletonGraphic = GetComponent(); } } #endif } } #endif ================================================ FILE: VirtueSky/Component/SkeletonComponent/SkinSkeleton/SkinSkeletonUIComponent.cs.meta ================================================ fileFormatVersion: 2 guid: 98a5b0f9dbf84aec9ebc52442d5bbe16 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Component/SkeletonComponent/SkinSkeleton.meta ================================================ fileFormatVersion: 2 guid: 998923b56f42400469041e4440a898bf folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Component/SkeletonComponent.meta ================================================ fileFormatVersion: 2 guid: 9f90ca78d90fcd84fa3aec9942675b57 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Component/TimeRemainingComponent.cs ================================================ using System; using UnityEngine; using VirtueSky.Core; using VirtueSky.Inspector; namespace VirtueSky.Component { [EditorIcon("icon_csharp"), HideMonoScript] public class TimeRemainingComponent : BaseMono { [SerializeField] private int targetYear; [SerializeField] private int targetMonth; [SerializeField] private int targetDay; [SerializeField] private int targetHour; [SerializeField] private int targetMinute; [SerializeField] private int targetSecond; private DateTime targetTime; public void InitTargetTime() { targetTime = new DateTime(targetYear, targetMonth, targetDay, targetHour, targetMinute, targetSecond); } public void InitTargetTime(int year, int month, int day, int hour, int minute, int second) { targetTime = new DateTime(year, month, day, hour, minute, second); } public TimeSpan GetTimeRemaining() { return (targetTime - DateTime.Now).TotalSeconds > 0 ? (targetTime - DateTime.Now) : TimeSpan.Zero; } } } ================================================ FILE: VirtueSky/Component/TimeRemainingComponent.cs.meta ================================================ fileFormatVersion: 2 guid: afeabd83b21c46eaa3666eb81ba90e20 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Component/virtuesky.sunflower.component.asmdef ================================================ { "name": "Virtuesky.Sunflower.Component", "rootNamespace": "", "references": [ "GUID:acb3cac55c622ec459c8caadf707623a", "GUID:80ecb87cae9c44d19824e70ea7229748", "GUID:72d1fea872bd7a449bf3818f2b0a6708", "GUID:68765d262e2128e4ab49c983f3411946", "GUID:f51ebe6a0ceec4240a699833d6309b23", "GUID:4c25c05f410a3a447a75c3b0909152ef", "GUID:324caed91501a9c47a04ebfd87b68794", "GUID:fca7ec166e04dc948b624a983315e2c9", "GUID:c282fd4f3fc2c7540914e85842a013c7" ], "includePlatforms": [], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], "versionDefines": [], "noEngineReferences": false } ================================================ FILE: VirtueSky/Component/virtuesky.sunflower.component.asmdef.meta ================================================ fileFormatVersion: 2 guid: 9fb70e528497d88469e13fc11e3eb30e AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Component.meta ================================================ fileFormatVersion: 2 guid: e48d2f41f2ea4bc3ab451313aeb9b63c timeCreated: 1697785718 ================================================ FILE: VirtueSky/ControlPanel/CPAboutDrawer.cs ================================================ using System; using UnityEditor; using UnityEngine; using VirtueSky.UtilsEditor; namespace VirtueSky.ControlPanel.Editor { public class CPAboutDrawer { public static void OnDrawAbout(Rect position, Action drawSetting = null) { GUILayout.Space(10); GUILayout.BeginVertical(); GUILayout.BeginHorizontal(); GUILayout.BeginVertical(); CPUtility.DrawHeaderIcon(StatePanelControl.About, "About"); GUILayout.Space(10); GUILayout.TextArea("Name: Sunflower", EditorStyles.boldLabel); GUILayout.TextArea( "Description: Core ScriptableObject architecture for building Unity games", EditorStyles.boldLabel); GUILayout.TextArea($"Version: {ConstantPackage.VersionSunflower}", EditorStyles.boldLabel); GUILayout.TextArea("Author: VirtueSky", EditorStyles.boldLabel); GUILayout.Space(10); if (GUILayout.Button("Open GitHub Repository")) { Application.OpenURL("https://github.com/VirtueSky/sunflower"); } if (GUILayout.Button("Document")) { Application.OpenURL("https://github.com/VirtueSky/sunflower/wiki"); } GUILayout.Space(10); GUILayout.EndVertical(); GUILayout.Box(EditorResources.IconVirtueSky, GUIStyle.none, GUILayout.Width(180), GUILayout.Height(180)); GUILayout.EndHorizontal(); GUILayout.Space(10); CPUtility.DrawLineLastRectY(3, ConstantControlPanel.POSITION_X_START_CONTENT, position.width); GUILayout.EndVertical(); } } } ================================================ FILE: VirtueSky/ControlPanel/CPAboutDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: cfde9ce3b42341abbdc803fd81396955 timeCreated: 1704944352 ================================================ FILE: VirtueSky/ControlPanel/CPAdjustDrawer.cs ================================================ using UnityEditor; using UnityEngine; using VirtueSky.Tracking; using VirtueSky.UtilsEditor; namespace VirtueSky.ControlPanel.Editor { public class CPAdjustDrawer { private static VirtueSky.Tracking.AdjustConfig _config; private static UnityEditor.Editor _editor; public static void OnEnable() { Init(); } private static void Init() { if (_editor != null) _editor = null; _config = CreateAsset.GetScriptableAsset(); _editor = UnityEditor.Editor.CreateEditor(_config); } public static void OnDrawAdjust() { GUILayout.Space(10); GUILayout.BeginVertical(); CPUtility.DrawHeaderIcon(StatePanelControl.Adjust, "Adjust"); GUILayout.Space(10); CPUtility.DrawButtonInstallPackage("Install Adjust", "Remove Adjust", ConstantPackage.PackageNameAdjust, ConstantPackage.MaxVersionAdjust); GUILayout.Space(10); CPUtility.GuiLine(2); GUILayout.Space(10); CPUtility.DrawHeader("Add define symbols"); GUILayout.Space(10); #if !VIRTUESKY_ADJUST EditorGUILayout.HelpBox( $"Add scripting define symbols: {ConstantDefineSymbols.VIRTUESKY_ADJUST} for Adjust to use", MessageType.Info); #endif GUILayout.Space(10); CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_ADJUST); GUILayout.Space(10); CPUtility.GuiLine(2); CPUtility.DrawHeader("Adjust Config"); GUILayout.Space(10); if (_config == null) { if (GUILayout.Button("Create AdjustConfig")) { _config = CreateAsset.CreateAndGetScriptableAsset("/AdjustTracking/Resources", isPingAsset: false); Init(); } } else { if (_editor == null) { EditorGUILayout.HelpBox("Couldn't create the settings editor.", MessageType.Error); return; } else { _editor.OnInspectorGUI(); } } GUILayout.Space(10); CPUtility.GuiLine(2); GUILayout.Space(10); CPUtility.DrawHeader("Adjust Tracking"); GUILayout.Space(10); if (GUILayout.Button("Create Scriptable Tracking Adjust")) { TrackingWindowEditor.CreateTrackingAdjust(); } GUILayout.Space(10); GUILayout.Space(10); CPUtility.GuiLine(2); GUILayout.Space(10); CPUtility.DrawHeader("Ping AdjustConfig"); GUILayout.Space(10); if (GUILayout.Button("Ping")) { if (_config == null) { Debug.LogError("AdjustConfig have not been created yet"); } else { EditorGUIUtility.PingObject(_config); Selection.activeObject = _config; } } GUILayout.Space(10); GUILayout.EndVertical(); } } } ================================================ FILE: VirtueSky/ControlPanel/CPAdjustDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: b93284e9903c4672ae0688d4a5b5294b timeCreated: 1717511923 ================================================ FILE: VirtueSky/ControlPanel/CPAdvertisingDrawer.cs ================================================ using UnityEditor; using UnityEngine; using VirtueSky.Ads; using VirtueSky.Inspector; using VirtueSky.UtilsEditor; namespace VirtueSky.ControlPanel.Editor { public class CPAdvertisingDrawer { private static Vector2 _scrollPosition; private static UnityEditor.Editor _editor; private static AdSetting _adSetting; private static Vector2 scroll = Vector2.zero; public static void OnEnable() { Init(); } public static void Init() { if (_editor != null) { _editor = null; } _adSetting = CreateAsset.GetScriptableAsset(); _editor = UnityEditor.Editor.CreateEditor(_adSetting); } public static void OnDrawAdvertising() { GUILayout.Space(10); GUILayout.BeginVertical(); CPUtility.DrawHeaderIcon(StatePanelControl.Advertising, "Advertising"); GUILayout.Space(10); scroll = EditorGUILayout.BeginScrollView(scroll); if (_adSetting == null) { if (GUILayout.Button("Create AdSetting")) { _adSetting = CreateAsset.CreateAndGetScriptableAsset("/Ads/Setting", isPingAsset: false); Init(); } } else { if (_editor == null) { EditorGUILayout.HelpBox("Couldn't create the settings resources editor.", MessageType.Error); return; } else { _editor.OnInspectorGUI(); } DrawDefineSymbols(); DrawInstallSdk(); } GUILayout.Space(10); CPUtility.GuiLine(2); GUILayout.Space(10); CPUtility.DrawHeader("Ping Ads Settings"); GUILayout.Space(10); if (GUILayout.Button("Ping")) { if (_adSetting == null) { Debug.LogError("AdSetting have not been created yet"); } else { EditorGUIUtility.PingObject(_adSetting); Selection.activeObject = _adSetting; } } GUILayout.Space(10); EditorGUILayout.EndScrollView(); GUILayout.EndVertical(); } static void DrawDefineSymbols() { GUILayout.Space(10); CPUtility.GuiLine(2); GUILayout.Space(10); CPUtility.DrawHeader("Define Symbols"); GUILayout.Space(10); CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_ADS); if (_adSetting.UseAppLovin) { #if !VIRTUESKY_ADS || !VIRTUESKY_APPLOVIN EditorGUILayout.HelpBox( $"Add scripting define symbols \"{ConstantDefineSymbols.VIRTUESKY_ADS}\" and \"{ConstantDefineSymbols.VIRTUESKY_APPLOVIN}\" to use Max Ads", MessageType.Info); #endif CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_APPLOVIN); } if (_adSetting.UseAdmob) { #if !VIRTUESKY_ADS || !VIRTUESKY_ADMOB EditorGUILayout.HelpBox( $"Add scripting define symbols \"{ConstantDefineSymbols.VIRTUESKY_ADS}\" and \"{ConstantDefineSymbols.VIRTUESKY_ADMOB}\" to use Admob Ads", MessageType.Info); #endif CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_ADMOB); } if (_adSetting.UseLevelPlay) { #if !VIRTUESKY_ADS || !VIRTUESKY_LEVELPLAY EditorGUILayout.HelpBox( $"Add scripting define symbols \"{ConstantDefineSymbols.VIRTUESKY_ADS}\" and \"{ConstantDefineSymbols.VIRTUESKY_LEVELPLAY}\" to use IronSource Ads", MessageType.Info); #endif CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_LEVELPLAY); } } static void DrawInstallSdk() { GUILayout.Space(10); CPUtility.GuiLine(2); GUILayout.Space(10); CPUtility.DrawHeader("Install Sdk"); GUILayout.Space(10); if (_adSetting.UseAppLovin) { GUILayout.Space(10); if (GUILayout.Button("Install Max Sdk Plugin")) { AssetDatabase.ImportPackage( FileExtension.GetPathFileInCurrentEnvironment( "VirtueSky/Utils/Editor/UnityPackage/max-sdk.unitypackage"), false); } } if (_adSetting.UseAdmob) { GUILayout.Space(10); CPUtility.DrawButtonInstallPackage("Install Admob Sdk Plugin", "Remove Admob Sdk Plugin", ConstantPackage.PackageNameAdmob, ConstantPackage.VersionAdmob); } if (_adSetting.UseLevelPlay) { GUILayout.Space(10); CPUtility.DrawButtonInstallPackage("Install LevelPlay Sdk Plugin", "Remove LevelPlay Sdk Plugin", ConstantPackage.PackageNameLevelPlay, ConstantPackage.MaxVersionLevelPlay); } } } } ================================================ FILE: VirtueSky/ControlPanel/CPAdvertisingDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: 99b17fe6aaad476ca0806f0d593479b1 timeCreated: 1704942542 ================================================ FILE: VirtueSky/ControlPanel/CPAppsFlyerDrawer.cs ================================================ using UnityEditor; using UnityEngine; using VirtueSky.Tracking; using VirtueSky.UtilsEditor; namespace VirtueSky.ControlPanel.Editor { public class CPAppsFlyerDrawer { private static VirtueSky.Tracking.AppsFlyerConfig _config; private static UnityEditor.Editor _editor; private static Vector2 scroll = Vector2.zero; public static void OnEnable() { Init(); } private static void Init() { if (_editor != null) _editor = null; _config = CreateAsset.GetScriptableAsset(); _editor = UnityEditor.Editor.CreateEditor(_config); } public static void OnDrawAppsFlyer() { GUILayout.Space(10); GUILayout.BeginVertical(); CPUtility.DrawHeaderIcon(StatePanelControl.AppsFlyer, "AppsFlyer"); GUILayout.Space(10); scroll = EditorGUILayout.BeginScrollView(scroll); CPUtility.DrawButtonInstallPackage("Install AppsFlyer", "Remove AppsFlyer", ConstantPackage.PackageNameAppFlyer, ConstantPackage.MaxVersionAppFlyer); GUILayout.Space(10); CPUtility.GuiLine(2); GUILayout.Space(10); #if !VIRTUESKY_APPSFLYER EditorGUILayout.HelpBox( $"Add scripting define symbols: {ConstantDefineSymbols.VIRTUESKY_APPSFLYER} for AppsFlyer to use", MessageType.Info); #endif GUILayout.Space(10); CPUtility.DrawHeader("Define Symbols"); GUILayout.Space(10); CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_APPSFLYER); GUILayout.Space(10); CPUtility.GuiLine(2); CPUtility.DrawHeader("AppsFlyer Config"); GUILayout.Space(10); if (_config == null) { if (GUILayout.Button("Create AppsFlyerConfig")) { _config = CreateAsset.CreateAndGetScriptableAsset( "/AppsFlyerTracking/Resources", isPingAsset: false); Init(); } } else { if (_editor == null) { EditorGUILayout.HelpBox("Couldn't create the settings editor.", MessageType.Error); return; } else { EditorGUILayout.HelpBox( "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.", MessageType.Info); _editor.OnInspectorGUI(); } } GUILayout.Space(10); CPUtility.GuiLine(2); CPUtility.DrawHeader("AppsFlyer Tracking"); GUILayout.Space(10); if (GUILayout.Button("Create Scriptable Tracking AppsFlyer No Param")) { TrackingWindowEditor.CreateTrackingAfNoParam(); } if (GUILayout.Button("Create Scriptable Tracking AppsFlyer 1 Param")) { TrackingWindowEditor.CreateTrackingAf1Param(); } if (GUILayout.Button("Create Scriptable Tracking AppsFlyer 2 Param")) { TrackingWindowEditor.CreateTrackingAf2Param(); } if (GUILayout.Button("Create Scriptable Tracking AppsFlyer 3 Param")) { TrackingWindowEditor.CreateTrackingAf3Param(); } if (GUILayout.Button("Create Scriptable Tracking AppsFlyer 4 Param")) { TrackingWindowEditor.CreateTrackingAf4Param(); } if (GUILayout.Button("Create Scriptable Tracking AppsFlyer 5 Param")) { TrackingWindowEditor.CreateTrackingAf5Param(); } if (GUILayout.Button("Create Scriptable Tracking AppsFlyer Has Param")) { TrackingWindowEditor.CreateTrackingAfHasParam(); } GUILayout.Space(10); GUILayout.Space(10); CPUtility.GuiLine(2); GUILayout.Space(10); CPUtility.DrawHeader("Ping AppsflyerConfig"); GUILayout.Space(10); if (GUILayout.Button("Ping")) { if (_config == null) { Debug.LogError("AppsflyerConfig have not been created yet"); } else { EditorGUIUtility.PingObject(_config); Selection.activeObject = _config; } } GUILayout.Space(10); EditorGUILayout.EndScrollView(); GUILayout.EndVertical(); } } } ================================================ FILE: VirtueSky/ControlPanel/CPAppsFlyerDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: cd27eebd6e2b4e7eafee9a99847442ba timeCreated: 1717512747 ================================================ FILE: VirtueSky/ControlPanel/CPAssetFinderDrawer.cs ================================================ using UnityEditor; using UnityEngine; using VirtueSky.AssetFinder.Editor; using VirtueSky.UtilsEditor; //using VirtueSky.AssetFinder.Editor; namespace VirtueSky.ControlPanel.Editor { public static class CPAssetFinderDrawer { public static void OnDrawAssetUsageDetector() { GUILayout.Space(10); GUILayout.BeginVertical(); CPUtility.DrawHeaderIcon(StatePanelControl.AssetsFinder, "Asset Finder"); GUILayout.Space(10); if (GUILayout.Button("Open Asset Finder Window (Ctrl+Shift+K / Command+Shift+K)")) { AssetFinderWindowExtension.ShowWindow(); } if (GUILayout.Button("Delete Finder Cache")) { AssetFinderWindowExtension.DeleteCache(); } GUILayout.Space(10); CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.ASSET_FINDER_ADDRESSABLE); GUILayout.EndVertical(); } } } ================================================ FILE: VirtueSky/ControlPanel/CPAssetFinderDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: 70672f20e14648029029064a97d8aaec timeCreated: 1704943341 ================================================ FILE: VirtueSky/ControlPanel/CPAudioDrawer.cs ================================================ using System; using System.Collections.Generic; using UnityEditor; using UnityEngine; using VirtueSky.Audio; using VirtueSky.AudioEditor; using Object = UnityEngine.Object; namespace VirtueSky.ControlPanel.Editor { public static class CPAudioDrawer { #region Constants private static class LayoutConstants { public const float PANEL_SPACING = 20f; public const float LEFT_PANEL_MARGIN = 15f; public const float RIGHT_PANEL_MARGIN = 30f; public const float BUTTON_HEIGHT = 25f; public const float HEADER_SPACING = 10f; public const float LINE_THICKNESS = 3f; public const float PING_BUTTON_WIDTH = 100f; public const float QUICK_ACTION_BUTTON_WIDTH = 80f; public const int TEXTURE_SIZE = 2; } private static readonly Color SELECTED_BUTTON_COLOR = new Color(0.3f, 0.5f, 0.85f, 1f); #endregion #region Fields public enum AudioTab { Explore, Settings } private static AudioTab audioTab = AudioTab.Explore; private static SoundData selectedSoundData; private static UnityEditor.Editor soundDataEditor; private static EditorWindow hostWindow; private static Vector2 leftPanelScrollPosition = Vector2.zero; private static Vector2 rightPanelScrollPosition = Vector2.zero; private static Texture2D selectedButtonTexture; private static Texture2D normalButtonTexture; private static GUIStyle normalButtonStyle; private static GUIStyle selectedButtonStyle; private static List cachedSoundDataAssets; private static bool needsRefresh = true; private static string searchFilter = ""; private static SoundData renamingSoundData; private static string renamingText = ""; private static bool isRenaming = false; #endregion #region Initialization & Cleanup [UnityEditor.InitializeOnLoadMethod] private static void Initialize() { EditorApplication.quitting += Cleanup; } [UnityEditor.Callbacks.DidReloadScripts] private static void OnScriptsReloaded() { needsRefresh = true; } private static void Cleanup() { DestroyTexture(ref selectedButtonTexture); DestroyTexture(ref normalButtonTexture); DestroyEditor(ref soundDataEditor); cachedSoundDataAssets?.Clear(); cachedSoundDataAssets = null; normalButtonStyle = null; selectedButtonStyle = null; } private static void DestroyTexture(ref Texture2D texture) { if (texture != null) { Object.DestroyImmediate(texture); texture = null; } } private static void DestroyEditor(ref UnityEditor.Editor editor) { if (editor != null) { Object.DestroyImmediate(editor); editor = null; } } #endregion #region Asset Management private static List GetSoundDataAssets() { if (cachedSoundDataAssets == null || needsRefresh) { RefreshSoundDataAssets(); } return cachedSoundDataAssets; } private static void RefreshSoundDataAssets() { var soundDataGuids = AssetDatabase.FindAssets("t:SoundData"); cachedSoundDataAssets = new List(soundDataGuids.Length); foreach (var guid in soundDataGuids) { string assetPath = AssetDatabase.GUIDToAssetPath(guid); var soundData = AssetDatabase.LoadAssetAtPath(assetPath); if (soundData != null) { cachedSoundDataAssets.Add(soundData); } } cachedSoundDataAssets.Sort((a, b) => string.Compare(a.name, b.name, System.StringComparison.Ordinal)); needsRefresh = false; } private static List GetFilteredSoundDataAssets() { var allAssets = GetSoundDataAssets(); if (string.IsNullOrWhiteSpace(searchFilter)) return allAssets; return allAssets.FindAll(sd => sd.name.IndexOf(searchFilter, System.StringComparison.OrdinalIgnoreCase) >= 0); } #endregion #region Style Management private static void InitializeStyles() { if (normalButtonStyle == null) { normalButtonStyle = new GUIStyle(GUI.skin.button); } if (selectedButtonStyle == null) { selectedButtonStyle = new GUIStyle(GUI.skin.button); if (selectedButtonTexture == null) { selectedButtonTexture = MakeBackgroundTexture( LayoutConstants.TEXTURE_SIZE, SELECTED_BUTTON_COLOR); } selectedButtonStyle.normal.background = selectedButtonTexture; selectedButtonStyle.onNormal.background = selectedButtonTexture; selectedButtonStyle.normal.textColor = Color.white; selectedButtonStyle.hover.background = selectedButtonTexture; } } private static Texture2D MakeBackgroundTexture(int size, Color color) { int pixelCount = size * size; Color[] pixels = new Color[pixelCount]; for (int i = 0; i < pixelCount; i++) { pixels[i] = color; } Texture2D texture = new Texture2D(size, size); texture.SetPixels(pixels); texture.Apply(); return texture; } #endregion #region Main Drawing public static void OnDrawAudio(Rect position, EditorWindow ownerWindow) { hostWindow = ownerWindow; GUILayout.Space(LayoutConstants.HEADER_SPACING); GUILayout.BeginVertical(); CPUtility.DrawHeaderIcon(StatePanelControl.Audio, "Audio"); GUILayout.Space(LayoutConstants.HEADER_SPACING); DrawTab(); GUILayout.Space(LayoutConstants.HEADER_SPACING); CPUtility.GuiLine(2); GUILayout.Space(LayoutConstants.HEADER_SPACING); switch (audioTab) { case AudioTab.Explore: DrawExplore(position); break; case AudioTab.Settings: DrawSetting(position); break; } GUILayout.EndVertical(); } private static void DrawTab() { EditorGUILayout.BeginHorizontal(); if (GUILayout.Toggle(audioTab == AudioTab.Explore, "Explore", GUI.skin.button, GUILayout.ExpandWidth(true), GUILayout.Height(LayoutConstants.BUTTON_HEIGHT))) { audioTab = AudioTab.Explore; } if (GUILayout.Toggle(audioTab == AudioTab.Settings, "Setting", GUI.skin.button, GUILayout.ExpandWidth(true), GUILayout.Height(LayoutConstants.BUTTON_HEIGHT))) { audioTab = AudioTab.Settings; } EditorGUILayout.EndHorizontal(); } #endregion #region Explore Tab private static void DrawExplore(Rect position) { CPUtility.DrawLineLastRectX( LayoutConstants.LINE_THICKNESS, GUILayoutUtility.GetLastRect().y, position.width, (position.width - ConstantControlPanel.POSITION_X_START_CONTENT) / 2 - 5); float leftPanelWidth = (position.width - ConstantControlPanel.POSITION_X_START_CONTENT) / 2 - LayoutConstants.LEFT_PANEL_MARGIN; float rightPanelWidth = position.width - ConstantControlPanel.POSITION_X_START_CONTENT - leftPanelWidth - LayoutConstants.RIGHT_PANEL_MARGIN; GUILayout.BeginHorizontal(); GUILayout.BeginVertical(GUILayout.Width(leftPanelWidth)); DrawLeftExplore(); GUILayout.EndVertical(); GUILayout.Space(LayoutConstants.PANEL_SPACING); GUILayout.BeginVertical(GUILayout.Width(rightPanelWidth)); DrawRightExplore(); GUILayout.EndVertical(); GUILayout.EndHorizontal(); } private static void DrawLeftExplore() { DrawSearchBar(); GUILayout.Space(5); DrawQuickActions(); GUILayout.Space(5); // Handle keyboard input before scrollview to capture events HandleKeyboardInput(); leftPanelScrollPosition = GUILayout.BeginScrollView( leftPanelScrollPosition, GUILayout.ExpandHeight(true)); InitializeStyles(); var filteredAssets = GetFilteredSoundDataAssets(); foreach (var soundData in filteredAssets) { if (soundData != null) { DrawSoundDataButton(soundData); } } GUILayout.EndScrollView(); } private static void DrawSearchBar() { GUILayout.BeginHorizontal(); GUILayout.Label("Search:", GUILayout.Width(60)); EditorGUI.BeginChangeCheck(); var searchFieldStyle = GUI.skin.FindStyle("ToolbarSearchTextField") ?? GUI.skin.textField; searchFilter = GUILayout.TextField(searchFilter, searchFieldStyle); if (EditorGUI.EndChangeCheck()) { var filtered = GetFilteredSoundDataAssets(); if (filtered.Count > 0 && !filtered.Contains(selectedSoundData)) { SelectSoundData(filtered[0]); } } if (GUILayout.Button("×", GUILayout.Width(20))) { searchFilter = ""; GUI.FocusControl(null); } GUILayout.EndHorizontal(); } private static void DrawQuickActions() { GUILayout.BeginHorizontal(); if (GUILayout.Button("Refresh", GUILayout.Width(LayoutConstants.QUICK_ACTION_BUTTON_WIDTH))) { RefreshSoundDataAssets(); } if (GUILayout.Button("Create New", GUILayout.Width(LayoutConstants.QUICK_ACTION_BUTTON_WIDTH))) { AudioWindowEditor.CreateSoundData(); needsRefresh = true; } GUILayout.FlexibleSpace(); var filteredCount = GetFilteredSoundDataAssets().Count; var totalCount = GetSoundDataAssets().Count; string countText = filteredCount == totalCount ? $"Total: {totalCount}" : $"Showing: {filteredCount}/{totalCount}"; GUILayout.Label(countText, EditorStyles.miniLabel); GUILayout.EndHorizontal(); } private static void DrawSoundDataButton(SoundData soundData) { if (isRenaming && renamingSoundData == soundData) { DrawRenamingField(soundData); } else { DrawNormalButton(soundData); } } private static void DrawNormalButton(SoundData soundData) { var style = (selectedSoundData == soundData) ? selectedButtonStyle : normalButtonStyle; var rect = GUILayoutUtility.GetRect(new GUIContent(soundData.name), style, GUILayout.ExpandWidth(true)); // Handle events BEFORE button to capture them Event evt = Event.current; // Handle double-click if (evt.type == EventType.MouseDown && evt.clickCount == 2 && evt.button == 0 && rect.Contains(evt.mousePosition)) { StartRename(soundData); evt.Use(); return; } // Handle right-click if (evt.type == EventType.ContextClick && rect.Contains(evt.mousePosition)) { ShowSoundDataContextMenu(soundData); evt.Use(); return; } // Normal button click if (GUI.Button(rect, soundData.name, style)) { SelectSoundData(soundData); } } private static void DrawRenamingField(SoundData soundData) { GUILayout.BeginHorizontal(); GUI.SetNextControlName("RenameField"); renamingText = GUILayout.TextField(renamingText, GUILayout.ExpandWidth(true)); if (GUILayout.Button("✓", GUILayout.Width(25))) { ConfirmRename(soundData); } if (GUILayout.Button("✕", GUILayout.Width(25))) { CancelRename(); } GUILayout.EndHorizontal(); HandleRenameFieldEvents(); } private static void HandleRenameFieldEvents() { Event evt = Event.current; if (evt.type == EventType.KeyDown) { if (evt.keyCode == KeyCode.Return || evt.keyCode == KeyCode.KeypadEnter) { ConfirmRename(renamingSoundData); evt.Use(); } else if (evt.keyCode == KeyCode.Escape) { CancelRename(); evt.Use(); } } if (isRenaming && GUI.GetNameOfFocusedControl() != "RenameField") { GUI.FocusControl("RenameField"); } } private static void StartRename(SoundData soundData) { renamingSoundData = soundData; renamingText = soundData.name; isRenaming = true; GUI.FocusControl("RenameField"); } private static void ConfirmRename(SoundData soundData) { if (string.IsNullOrWhiteSpace(renamingText)) { EditorUtility.DisplayDialog("Invalid Name", "Asset name cannot be empty!", "OK"); return; } if (renamingText == soundData.name) { CancelRename(); return; } string assetPath = AssetDatabase.GetAssetPath(soundData); string errorMessage = AssetDatabase.RenameAsset(assetPath, renamingText); if (!string.IsNullOrEmpty(errorMessage)) { EditorUtility.DisplayDialog("Rename Failed", errorMessage, "OK"); } else { AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); needsRefresh = true; } CancelRename(); } private static void CancelRename() { isRenaming = false; renamingSoundData = null; renamingText = ""; GUI.FocusControl(null); } private static void ShowSoundDataContextMenu(SoundData soundData) { GenericMenu menu = new GenericMenu(); menu.AddItem(new GUIContent("Rename"), false, () => { StartRename(soundData); }); menu.AddSeparator(""); menu.AddItem(new GUIContent("Ping in Project"), false, () => { Selection.activeObject = soundData; EditorGUIUtility.PingObject(soundData); }); menu.AddItem(new GUIContent("Duplicate"), false, () => { var path = AssetDatabase.GetAssetPath(soundData); var newPath = AssetDatabase.GenerateUniqueAssetPath(path); AssetDatabase.CopyAsset(path, newPath); AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); needsRefresh = true; }); menu.AddSeparator(""); menu.AddItem(new GUIContent("Delete"), false, () => { if (EditorUtility.DisplayDialog("Delete SoundData", $"Are you sure you want to delete '{soundData.name}'?", "Delete", "Cancel")) { var path = AssetDatabase.GetAssetPath(soundData); AssetDatabase.DeleteAsset(path); if (selectedSoundData == soundData) { selectedSoundData = null; DestroyEditor(ref soundDataEditor); } AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); needsRefresh = true; } }); menu.ShowAsContext(); } private static void SelectSoundData(SoundData soundData) { if (selectedSoundData != soundData) { selectedSoundData = soundData; DestroyEditor(ref soundDataEditor); } } private static void DrawRightExplore() { rightPanelScrollPosition = GUILayout.BeginScrollView( rightPanelScrollPosition, GUILayout.ExpandHeight(true)); if (selectedSoundData != null) { DrawPingButton(); GUILayout.Space(5); DrawSoundDataEditor(); } else { GUILayout.Label("No SoundData selected", EditorStyles.centeredGreyMiniLabel); } GUILayout.EndScrollView(); } private static void DrawPingButton() { GUILayout.BeginHorizontal(); if (GUILayout.Button("Ping Asset", GUILayout.Width(LayoutConstants.PING_BUTTON_WIDTH))) { EditorGUIUtility.PingObject(selectedSoundData); Selection.activeObject = selectedSoundData; } GUILayout.EndHorizontal(); } private static void DrawSoundDataEditor() { if (soundDataEditor == null || (soundDataEditor.target as SoundData) != selectedSoundData) { DestroyEditor(ref soundDataEditor); soundDataEditor = UnityEditor.Editor.CreateEditor(selectedSoundData); } if (soundDataEditor != null) { if (soundDataEditor is SoundDataEditor sdEditor) { sdEditor.SetExternalRepaintCallback(hostWindow != null ? new Action(hostWindow.Repaint) : null); } EditorGUI.BeginChangeCheck(); soundDataEditor.OnInspectorGUI(); if (EditorGUI.EndChangeCheck()) { EditorUtility.SetDirty(selectedSoundData); } } } private static void HandleKeyboardInput() { if (isRenaming) return; Event evt = Event.current; // Accept both KeyDown and KeyUp for better compatibility if (evt.type != EventType.KeyDown && evt.type != EventType.KeyUp) return; // Only process on KeyDown to avoid double-processing if (evt.type != EventType.KeyDown) return; var assets = GetFilteredSoundDataAssets(); int currentIndex = assets.IndexOf(selectedSoundData); switch (evt.keyCode) { case KeyCode.F2: if (selectedSoundData != null) { StartRename(selectedSoundData); evt.Use(); GUI.changed = true; } break; case KeyCode.UpArrow: if (currentIndex > 0) { SelectSoundData(assets[currentIndex - 1]); evt.Use(); } break; case KeyCode.DownArrow: if (currentIndex >= 0 && currentIndex < assets.Count - 1) { SelectSoundData(assets[currentIndex + 1]); evt.Use(); } break; case KeyCode.Return: case KeyCode.KeypadEnter: if (selectedSoundData != null) { EditorGUIUtility.PingObject(selectedSoundData); Selection.activeObject = selectedSoundData; evt.Use(); } break; case KeyCode.Delete: case KeyCode.Backspace: if (selectedSoundData != null && evt.command == false && evt.control == false) { if (EditorUtility.DisplayDialog("Delete SoundData", $"Are you sure you want to delete '{selectedSoundData.name}'?", "Delete", "Cancel")) { var path = AssetDatabase.GetAssetPath(selectedSoundData); AssetDatabase.DeleteAsset(path); selectedSoundData = null; DestroyEditor(ref soundDataEditor); AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); needsRefresh = true; } evt.Use(); } break; } } #endregion #region Settings Tab private static void DrawSetting(Rect position) { DrawCreateSoundDataSection(); DrawSectionSeparator(position); DrawMusicEventSection(); DrawSectionSeparator(position); DrawSfxEventSection(); DrawSectionSeparator(position); DrawVolumeVariableSection(); } private static void DrawSectionSeparator(Rect position) { GUILayout.Space(LayoutConstants.HEADER_SPACING); CPUtility.DrawLineLastRectY( LayoutConstants.LINE_THICKNESS, ConstantControlPanel.POSITION_X_START_CONTENT, position.width); GUILayout.Space(LayoutConstants.HEADER_SPACING); } private static void DrawCreateSoundDataSection() { if (GUILayout.Button("Create Sound Data")) { AudioWindowEditor.CreateSoundData(); needsRefresh = true; } } private static void DrawMusicEventSection() { CPUtility.DrawHeader("Music Event"); GUILayout.Space(LayoutConstants.HEADER_SPACING); DrawButton("Create Play Music Event", AudioWindowEditor.CreatePlayMusicEvent); DrawButton("Create Pause Music Event", AudioWindowEditor.CreatePauseMusicEvent); DrawButton("Create Resume Music Event", AudioWindowEditor.CreateResumeMusicEvent); DrawButton("Create Stop Music Event", AudioWindowEditor.CreateStopMusicEvent); } private static void DrawSfxEventSection() { CPUtility.DrawHeader("Sfx Event"); GUILayout.Space(LayoutConstants.HEADER_SPACING); DrawButton("Create Play Sfx Event", AudioWindowEditor.CreatePlaySfxEvent); DrawButton("Create Pause Sfx Event", AudioWindowEditor.CreatePauseSfxEvent); DrawButton("Create Resume Sfx Event", AudioWindowEditor.CreateResumeSfxEvent); DrawButton("Create Finish Sfx Event", AudioWindowEditor.CreateFinishSfxEvent); DrawButton("Create Stop Sfx Event", AudioWindowEditor.CreateStopSfxEvent); DrawButton("Create Stop All Sfx Event", AudioWindowEditor.CreateStopAllSfxEvent); } private static void DrawVolumeVariableSection() { CPUtility.DrawHeader("Volume Changed Variable"); GUILayout.Space(LayoutConstants.HEADER_SPACING); DrawButton("Create Music Volume Variable", AudioWindowEditor.CreateMusicVolume); DrawButton("Create Sfx Volume Variable", AudioWindowEditor.CreateSfxVolume); } private static void DrawButton(string label, System.Action onClick) { if (GUILayout.Button(label)) { onClick?.Invoke(); } } #endregion } } ================================================ FILE: VirtueSky/ControlPanel/CPAudioDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: 75f998153cb84b05b39fde9bba92e154 timeCreated: 1704943417 ================================================ FILE: VirtueSky/ControlPanel/CPExtensionsDrawer.cs ================================================ using System.Diagnostics; using System.IO; using UnityEditor; using UnityEditor.Android; using UnityEngine; using VirtueSky.UtilsEditor; namespace VirtueSky.ControlPanel.Editor { public static class CPExtensionsDrawer { public static void OnDrawExtensions(Rect position) { GUILayout.Space(10); GUILayout.BeginVertical(); CPUtility.DrawHeaderIcon(StatePanelControl.Extensions, "Extensions"); #if UNITY_ANDROID GUILayout.Space(10); if (GUILayout.Button("Open Sdk")) { OpenSdkPath(); } if (GUILayout.Button("Open Jdk")) { OpenJdkPath(); } if (GUILayout.Button("Open Ndk")) { OpenNdkPath(); } if (GUILayout.Button("Open Gradle")) { OpenGradlePath(); } if (SystemInfo.operatingSystemFamily == OperatingSystemFamily.Windows) { GUILayout.Space(10); CPUtility.DrawLineLastRectY(3, ConstantControlPanel.POSITION_X_START_CONTENT, position.width); GUILayout.Space(10); EditorGUILayout.HelpBox("Monitor only works on java sdk 8", MessageType.Warning); if (GUILayout.Button("Open Monitor")) { OpenMonitor(); } } #endif GUILayout.EndVertical(); } #if UNITY_ANDROID static void OpenSdkPath() { var path = $"{AndroidExternalToolsSettings.sdkRootPath}/"; switch (SystemInfo.operatingSystemFamily) { case OperatingSystemFamily.Windows: FileExtension.OpenFolderInExplorer(path); break; case OperatingSystemFamily.MacOSX: FileExtension.OpenFolderInFinder(path); break; } } static void OpenJdkPath() { var path = $"{AndroidExternalToolsSettings.jdkRootPath}/"; switch (SystemInfo.operatingSystemFamily) { case OperatingSystemFamily.Windows: FileExtension.OpenFolderInExplorer(path); break; case OperatingSystemFamily.MacOSX: FileExtension.OpenFolderInFinder(path); break; } } static void OpenNdkPath() { var path = $"{AndroidExternalToolsSettings.ndkRootPath}/"; switch (SystemInfo.operatingSystemFamily) { case OperatingSystemFamily.Windows: FileExtension.OpenFolderInExplorer(path); break; case OperatingSystemFamily.MacOSX: FileExtension.OpenFolderInFinder(path); break; } } static void OpenGradlePath() { var path = $"{AndroidExternalToolsSettings.gradlePath}/"; switch (SystemInfo.operatingSystemFamily) { case OperatingSystemFamily.Windows: FileExtension.OpenFolderInExplorer(path); break; case OperatingSystemFamily.MacOSX: FileExtension.OpenFolderInFinder(path); break; } } static void OpenMonitor() { string path = $"{AndroidExternalToolsSettings.sdkRootPath}/tools/monitor.bat"; if (File.Exists(path)) { Process process = new Process(); process.StartInfo.FileName = path; process.StartInfo.Verb = "runas"; process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; process.Start(); } } #endif } } ================================================ FILE: VirtueSky/ControlPanel/CPExtensionsDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: 3eebf2e8a6bc4f81b7990a906df66bc7 timeCreated: 1709182260 ================================================ FILE: VirtueSky/ControlPanel/CPFirebaseDrawer.cs ================================================ using System.Diagnostics; using System.IO; using UnityEditor; using UnityEditor.Android; using UnityEngine; using VirtueSky.UtilsEditor; namespace VirtueSky.ControlPanel.Editor { public static class CPFirebaseDrawer { private static bool isShowInstallRemoteConfig = true; private static bool isShowInstallAnalytic = true; private static Vector2 scroll = Vector2.zero; private static bool isCustomPackageName; private static string packageName; public static void OnDrawFirebase(Rect position) { GUILayout.Space(10); GUILayout.BeginVertical(); CPUtility.DrawHeaderIcon(StatePanelControl.Firebase, "Firebase"); scroll = EditorGUILayout.BeginScrollView(scroll); DrawInstallFirebase(position); GUILayout.Space(10); CPUtility.GuiLine(2); GUILayout.Space(10); CPUtility.DrawHeader("Define Symbols"); GUILayout.Space(10); #if !VIRTUESKY_FIREBASE EditorGUILayout.HelpBox( $"Add scripting define symbols: {ConstantDefineSymbols.VIRTUESKY_FIREBASE} for Firebase App", MessageType.Info); #endif CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_FIREBASE); #if !VIRTUESKY_FIREBASE_REMOTECONFIG EditorGUILayout.HelpBox( $"Add scripting define symbols: {ConstantDefineSymbols.VIRTUESKY_FIREBASE_REMOTECONFIG} for Firebase Remote Config to use", MessageType.Info); #endif CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_FIREBASE_REMOTECONFIG); #if !VIRTUESKY_FIREBASE_ANALYTIC EditorGUILayout.HelpBox( $"Add scripting define symbols: {ConstantDefineSymbols.VIRTUESKY_FIREBASE_ANALYTIC} for Firebase Analytic to use", MessageType.Info); #endif CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_FIREBASE_ANALYTIC); GUILayout.Space(10); DrawTracking(position); #if UNITY_ANDROID CPUtility.GuiLine(2); DrawDebugView(); #endif GUILayout.Space(10); EditorGUILayout.EndScrollView(); GUILayout.EndVertical(); } static void DrawInstallFirebase(Rect position) { GUILayout.Space(20); isShowInstallRemoteConfig = GUILayout.Toggle(isShowInstallRemoteConfig, "Install Firebase Remote Config And Dependency"); GUILayout.Space(10); if (isShowInstallRemoteConfig) { CPUtility.DrawButtonInstallPackage("Install Firebase Remote Config", "Remove Firebase Remote Config", ConstantPackage.PackageNameFirebaseRemoteConfig, ConstantPackage.MaxVersionFirebaseRemoteConfig); CPUtility.DrawButtonInstallPackage("Install Firebase App", "Remove Firebase App", ConstantPackage.PackageNameFirebaseApp, ConstantPackage.MaxVersionFirebaseApp); CPUtility.DrawButtonInstallPackage("Install Google External Dependency Manager", "Remove Google External Dependency Manager", ConstantPackage.PackageNameGGExternalDependencyManager, ConstantPackage.MaxVersionGGExternalDependencyManager); } GUILayout.Space(10); isShowInstallAnalytic = GUILayout.Toggle(isShowInstallAnalytic, "Install Firebase Analytic And Dependency"); GUILayout.Space(10); if (isShowInstallAnalytic) { CPUtility.DrawButtonInstallPackage("Install Firebase Analytics", "Remove Firebase Analytics", ConstantPackage.PackageNameFirebaseAnalytics, ConstantPackage.MaxVersionFirebaseAnalytics); CPUtility.DrawButtonInstallPackage("Install Firebase App", "Remove Firebase App", ConstantPackage.PackageNameFirebaseApp, ConstantPackage.MaxVersionFirebaseApp); CPUtility.DrawButtonInstallPackage("Install Google External Dependency Manager", "Remove Google External Dependency Manager", ConstantPackage.PackageNameGGExternalDependencyManager, ConstantPackage.MaxVersionGGExternalDependencyManager); GUILayout.Space(10); } } static void DrawTracking(Rect position) { CPUtility.GuiLine(2); GUILayout.Space(10); CPUtility.DrawHeader("Firebase Tracking"); GUILayout.Space(10); if (GUILayout.Button("Create Scriptable Tracking Firebase No Param")) { TrackingWindowEditor.CreateLogEventFirebaseNoParam(); } if (GUILayout.Button("Create Scriptable Tracking Firebase 1 Param")) { TrackingWindowEditor.CreateLogEventFirebaseOneParam(); } if (GUILayout.Button("Create Scriptable Tracking Firebase 2 Param")) { TrackingWindowEditor.CreateLogEventFirebaseTwoParam(); } if (GUILayout.Button("Create Scriptable Tracking Firebase 3 Param")) { TrackingWindowEditor.CreateLogEventFirebaseThreeParam(); } if (GUILayout.Button("Create Scriptable Tracking Firebase 4 Param")) { TrackingWindowEditor.CreateLogEventFirebaseFourParam(); } if (GUILayout.Button("Create Scriptable Tracking Firebase 5 Param")) { TrackingWindowEditor.CreateLogEventFirebaseFiveParam(); } if (GUILayout.Button("Create Scriptable Tracking Firebase 6 Param")) { TrackingWindowEditor.CreateLogEventFirebaseSixParam(); } GUILayout.Space(10); } #if UNITY_ANDROID static void DrawDebugView() { GUILayout.Space(10); CPUtility.DrawHeader("Debug View"); GUILayout.Space(10); isCustomPackageName = EditorGUILayout.Toggle("Custom Package Name: ", isCustomPackageName); if (isCustomPackageName) { GUI.enabled = true; } else { packageName = Application.identifier; GUI.enabled = false; } packageName = EditorGUILayout.TextField("Package Name: ", packageName); GUI.enabled = true; GUILayout.BeginHorizontal(); if (GUILayout.Button("Run Debug View", GUILayout.Width(400))) { SetDebugView(packageName); } if (GUILayout.Button("Set None Debug View")) { SetDebugView(".none."); } GUILayout.EndHorizontal(); } static void SetDebugView(string package) { var fileName = $"{AndroidExternalToolsSettings.sdkRootPath}/platform-tools/adb"; var arguments = $"shell setprop debug.firebase.analytics.app {package}"; var startInfo = new ProcessStartInfo { FileName = fileName, UseShellExecute = false, RedirectStandardOutput = true, CreateNoWindow = true, Arguments = arguments, }; var process = Process.Start(startInfo); process!.WaitForExit(); UnityEngine.Debug.Log($"{fileName} {arguments}"); } #endif } } ================================================ FILE: VirtueSky/ControlPanel/CPFirebaseDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: 5d84391d37284f243863d41a6106102b MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/ControlPanel/CPFolderIconDrawer.cs ================================================ using UnityEditor; using UnityEngine; using Virtuesky.FolderIcon.Editor; using VirtueSky.UtilsEditor; namespace VirtueSky.ControlPanel.Editor { public class CPFolderIconDrawer { private static UnityEditor.Editor _editor; private static FolderIconSettings _settings; private static Vector2 scroll = Vector2.zero; public static void OnEnable() { Init(); } private static void Init() { if (_editor != null) { _editor = null; } _settings = CreateAsset.GetScriptableAsset(); _editor = UnityEditor.Editor.CreateEditor(_settings); } public static void OnDrawFolderIcon() { GUILayout.Space(10); GUILayout.BeginVertical(); CPUtility.DrawHeaderIcon(StatePanelControl.FolderIcon, "Folder Icon"); GUILayout.Space(10); scroll = EditorGUILayout.BeginScrollView(scroll); if (_settings == null) { if (GUILayout.Button("Create FolderIconSetting")) { _settings = CreateAsset.CreateAndGetScriptableAsset( "Assets/_Sunflower/Editor/FolderIconSettings", useDefaultPath: false); Init(); } } else { if (_editor == null) { EditorGUILayout.HelpBox("Couldn't create the settings editor.", MessageType.Error); return; } else { _editor.OnInspectorGUI(); GUILayout.Space(10); if (_settings.enableFolderIcons) { if (GUILayout.Button("Clear cache")) { _settings.ClearCache(); } GUILayout.Space(10); if (GUILayout.Button("Import texture icon folder")) { AssetDatabase.ImportPackage( FileExtension.GetPathFileInCurrentEnvironment( "VirtueSky/FolderIcon/Editor/PackageIcon/icon_folder.unitypackage"), false); } } } } EditorGUILayout.EndScrollView(); GUILayout.EndVertical(); } } } ================================================ FILE: VirtueSky/ControlPanel/CPFolderIconDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: 32daceff059c4ada87f6012ac05a1b19 timeCreated: 1722325833 ================================================ FILE: VirtueSky/ControlPanel/CPGameServiceDrawer.cs ================================================ using UnityEditor; using UnityEngine; using VirtueSky.UtilsEditor; namespace VirtueSky.ControlPanel.Editor { public static class CPGameServiceDrawer { public static void OnDrawGameService() { GUILayout.Space(10); GUILayout.BeginVertical(); CPUtility.DrawHeaderIcon(StatePanelControl.GameService, "Game Service"); GUILayout.Space(10); CPUtility.DrawButtonInstallPackage("Install Apple Sign In", "Remove Apple Sign In", ConstantPackage.PackageNameAppleSignIn, ConstantPackage.MaxVersionAppleSignIn); if (GUILayout.Button("Install Google Play Game Service", GUILayout.Width(400))) { AssetDatabase.ImportPackage( FileExtension.GetPathFileInCurrentEnvironment( "VirtueSky/Utils/Editor/UnityPackage/google-play-game.unitypackage"), false); } GUILayout.Space(10); CPUtility.GuiLine(); GUILayout.Space(10); CPUtility.DrawHeader("Define symbols"); GUILayout.Space(10); CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_APPLE_AUTH); CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_GPGS); GUILayout.EndVertical(); } } } ================================================ FILE: VirtueSky/ControlPanel/CPGameServiceDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: 39779f060a5248b88ca37991f3398939 timeCreated: 1706698019 ================================================ FILE: VirtueSky/ControlPanel/CPHierarchyDrawer.cs ================================================ using System; using System.Collections.Generic; using VirtueSky.Hierarchy.Data; using VirtueSky.Hierarchy.Helper; using UnityEditor; using UnityEngine; namespace VirtueSky.ControlPanel.Editor { public class CPHierarchyDrawer { public static void OnDrawQHierarchyEvent(Rect posittion, EditorWindow window) { GUILayout.Space(10); GUILayout.BeginVertical(); CPUtility.DrawHeaderIcon(StatePanelControl.Hierarchy, "Hierarchy"); GUILayout.Space(10); OnGUI(posittion, window); GUILayout.EndVertical(); } private static void init(EditorWindow window) { HierarchySettings.getInstance().inited = true; HierarchySettings.getInstance().isProSkin = EditorGUIUtility.isProSkin; HierarchySettings.getInstance().separatorColor = HierarchySettings.getInstance().isProSkin ? new Color(0.18f, 0.18f, 0.18f) : new Color(0.59f, 0.59f, 0.59f); HierarchySettings.getInstance().yellowColor = HierarchySettings.getInstance().isProSkin ? new Color(1.00f, 0.90f, 0.40f) : new Color(0.31f, 0.31f, 0.31f); HierarchySettings.getInstance().checkBoxChecked = HierarchyResources.getInstance() .getTexture(HierarchyTexture.HierarchyCheckBoxChecked); HierarchySettings.getInstance().checkBoxUnchecked = HierarchyResources.getInstance().getTexture(HierarchyTexture.HierarchyCheckBoxUnchecked); HierarchySettings.getInstance().restoreButtonTexture = HierarchyResources.getInstance() .getTexture(HierarchyTexture.HierarchyRestoreButton); HierarchySettings.getInstance().componentsOrderList = new HierarchyComponentsOrderList(window); } // GUI public static void OnGUI(Rect position, EditorWindow window) { if (!HierarchySettings.getInstance().inited || HierarchySettings.getInstance().isProSkin != EditorGUIUtility.isProSkin) init(window); HierarchySettings.getInstance().indentLevel = 8; HierarchySettings.getInstance().scrollPosition = EditorGUILayout.BeginScrollView(HierarchySettings.getInstance().scrollPosition); { Rect targetRect = EditorGUILayout.GetControlRect(GUILayout.Height(0)); if (Event.current.type == EventType.Repaint) HierarchySettings.getInstance().totalWidth = targetRect.width + 8; HierarchySettings.getInstance().lastRect = new Rect(0, 1, 0, 0); // COMPONENTS drawSection("COMPONENTS SETTINGS"); float sectionStartY = HierarchySettings.getInstance().lastRect.y + HierarchySettings.getInstance().lastRect.height; drawTreeMapComponentSettings(); drawSeparator(); drawMonoBehaviourIconComponentSettings(); drawSeparator(); drawSeparatorComponentSettings(); drawSeparator(); drawVisibilityComponentSettings(); drawSeparator(); drawLockComponentSettings(); drawSeparator(); drawStaticComponentSettings(); drawSeparator(); drawErrorComponentSettings(); drawSeparator(); drawRendererComponentSettings(); drawSeparator(); drawPrefabComponentSettings(); drawSeparator(); drawTagLayerComponentSettings(); drawSeparator(); drawColorComponentSettings(); drawSeparator(); drawGameObjectIconComponentSettings(); drawSeparator(); drawTagIconComponentSettings(); drawSeparator(); drawLayerIconComponentSettings(); drawSeparator(); drawChildrenCountComponentSettings(); drawSeparator(); drawVerticesAndTrianglesCountComponentSettings(); drawSeparator(); drawComponentsComponentSettings(); drawLeftLine(sectionStartY, HierarchySettings.getInstance().lastRect.y + HierarchySettings.getInstance().lastRect.height, HierarchySettings.getInstance().separatorColor); // ORDER drawSection("ORDER OF COMPONENTS"); sectionStartY = HierarchySettings.getInstance().lastRect.y + HierarchySettings.getInstance().lastRect.height; drawSpace(8); drawOrderSettings(position, window); drawSpace(6); drawLeftLine(sectionStartY, HierarchySettings.getInstance().lastRect.y + HierarchySettings.getInstance().lastRect.height, HierarchySettings.getInstance().separatorColor); // ADDITIONAL drawSection("ADDITIONAL SETTINGS"); sectionStartY = HierarchySettings.getInstance().lastRect.y + HierarchySettings.getInstance().lastRect.height; drawSpace(3); drawAdditionalSettings(); drawLeftLine(sectionStartY, HierarchySettings.getInstance().lastRect.y + HierarchySettings.getInstance().lastRect.height + 4, HierarchySettings.getInstance().separatorColor); HierarchySettings.getInstance().indentLevel -= 8; } EditorGUILayout.EndScrollView(); } // COMPONENTS private static void drawTreeMapComponentSettings() { if (drawComponentCheckBox("Hierarchy Tree", HierarchySetting.TreeMapShow)) { Rect rect = getControlRect(0, 0); if (drawRestore()) { HierarchySettings.getInstance().restore(HierarchySetting.TreeMapColor); HierarchySettings.getInstance().restore(HierarchySetting.TreeMapEnhanced); HierarchySettings.getInstance().restore(HierarchySetting.TreeMapTransparentBackground); } drawBackground(rect.x, rect.y, rect.width, 18 * 3 + 5); drawSpace(4); drawColorPicker("Tree color", HierarchySetting.TreeMapColor); drawCheckBoxRight("Transparent background", HierarchySetting.TreeMapTransparentBackground); drawCheckBoxRight("Enhanced (\"Transform Sort\" only)", HierarchySetting.TreeMapEnhanced); drawSpace(1); } } private static void drawMonoBehaviourIconComponentSettings() { if (drawComponentCheckBox("MonoBehaviour Icon", HierarchySetting.MonoBehaviourIconShow)) { Rect rect = getControlRect(0, 0); if (drawRestore()) { HierarchySettings.getInstance().restore(HierarchySetting.MonoBehaviourIconShowDuringPlayMode); HierarchySettings.getInstance().restore(HierarchySetting.MonoBehaviourIconColor); HierarchySettings.getInstance() .restore(HierarchySetting.MonoBehaviourIconIgnoreUnityMonobehaviour); } drawBackground(rect.x, rect.y, rect.width, 18 * 3 + 5); drawSpace(4); drawCheckBoxRight("Show component during play mode", HierarchySetting.MonoBehaviourIconShowDuringPlayMode); drawColorPicker("Icon color", HierarchySetting.MonoBehaviourIconColor); drawCheckBoxRight("Ignore Unity MonoBehaviours", HierarchySetting.MonoBehaviourIconIgnoreUnityMonobehaviour); drawSpace(1); } } private static void drawSeparatorComponentSettings() { if (drawComponentCheckBox("Separator", HierarchySetting.SeparatorShow)) { Rect rect = getControlRect(0, 0); if (drawRestore()) { HierarchySettings.getInstance().restore(HierarchySetting.SeparatorColor); HierarchySettings.getInstance().restore(HierarchySetting.SeparatorShowRowShading); HierarchySettings.getInstance().restore(HierarchySetting.SeparatorOddRowShadingColor); HierarchySettings.getInstance().restore(HierarchySetting.SeparatorEvenRowShadingColor); } bool rowShading = HierarchySettings.getInstance().get(HierarchySetting.SeparatorShowRowShading); drawBackground(rect.x, rect.y, rect.width, 18 * (rowShading ? 4 : 2) + 5); drawSpace(4); drawColorPicker("Separator Color", HierarchySetting.SeparatorColor); drawCheckBoxRight("Row shading", HierarchySetting.SeparatorShowRowShading); if (rowShading) { drawColorPicker("Even row shading color", HierarchySetting.SeparatorEvenRowShadingColor); drawColorPicker("Odd row shading color", HierarchySetting.SeparatorOddRowShadingColor); } drawSpace(1); } } private static void drawVisibilityComponentSettings() { if (drawComponentCheckBox("Visibility", HierarchySetting.VisibilityShow)) { Rect rect = getControlRect(0, 0); if (drawRestore()) { HierarchySettings.getInstance().restore(HierarchySetting.VisibilityShowDuringPlayMode); } drawBackground(rect.x, rect.y, rect.width, 18 + 5); drawSpace(4); drawCheckBoxRight("Show component during play mode", HierarchySetting.VisibilityShowDuringPlayMode); drawSpace(1); } } private static void drawLockComponentSettings() { if (drawComponentCheckBox("Lock", HierarchySetting.LockShow)) { Rect rect = getControlRect(0, 0); if (drawRestore()) { HierarchySettings.getInstance().restore(HierarchySetting.LockShowDuringPlayMode); HierarchySettings.getInstance().restore(HierarchySetting.LockPreventSelectionOfLockedObjects); } drawBackground(rect.x, rect.y, rect.width, 18 * 2 + 5); drawSpace(4); drawCheckBoxRight("Show component during play mode", HierarchySetting.LockShowDuringPlayMode); drawCheckBoxRight("Prevent selection of locked objects", HierarchySetting.LockPreventSelectionOfLockedObjects); drawSpace(1); } } private static void drawStaticComponentSettings() { if (drawComponentCheckBox("Static", HierarchySetting.StaticShow)) { Rect rect = getControlRect(0, 0); if (drawRestore()) { HierarchySettings.getInstance().restore(HierarchySetting.StaticShowDuringPlayMode); } drawBackground(rect.x, rect.y, rect.width, 18 + 5); drawSpace(4); drawCheckBoxRight("Show component during play mode", HierarchySetting.StaticShowDuringPlayMode); drawSpace(1); } } private static void drawErrorComponentSettings() { if (drawComponentCheckBox("Error", HierarchySetting.ErrorShow)) { Rect rect = getControlRect(0, 0); if (drawRestore()) { HierarchySettings.getInstance().restore(HierarchySetting.ErrorShowDuringPlayMode); HierarchySettings.getInstance().restore(HierarchySetting.ErrorShowIconOnParent); HierarchySettings.getInstance().restore(HierarchySetting.ErrorShowForDisabledComponents); HierarchySettings.getInstance().restore(HierarchySetting.ErrorShowForDisabledGameObjects); HierarchySettings.getInstance().restore(HierarchySetting.ErrorShowScriptIsMissing); HierarchySettings.getInstance().restore(HierarchySetting.ErrorShowReferenceIsMissing); HierarchySettings.getInstance().restore(HierarchySetting.ErrorShowReferenceIsNull); HierarchySettings.getInstance().restore(HierarchySetting.ErrorShowStringIsEmpty); HierarchySettings.getInstance().restore(HierarchySetting.ErrorShowMissingEventMethod); HierarchySettings.getInstance().restore(HierarchySetting.ErrorShowWhenTagOrLayerIsUndefined); HierarchySettings.getInstance().restore(HierarchySetting.ErrorIgnoreString); } drawBackground(rect.x, rect.y, rect.width, 18 * 12 + 5); drawSpace(4); drawCheckBoxRight("Show component during play mode", HierarchySetting.ErrorShowDuringPlayMode); drawCheckBoxRight("Show error icon up of hierarchy (very slow)", HierarchySetting.ErrorShowIconOnParent); drawCheckBoxRight("Show error icon for disabled components", HierarchySetting.ErrorShowForDisabledComponents); drawCheckBoxRight("Show error icon for disabled GameObjects", HierarchySetting.ErrorShowForDisabledGameObjects); drawLabel("Show error icon for the following:"); HierarchySettings.getInstance().indentLevel += 16; drawCheckBoxRight("- script is missing", HierarchySetting.ErrorShowScriptIsMissing); drawCheckBoxRight("- reference is missing", HierarchySetting.ErrorShowReferenceIsMissing); drawCheckBoxRight("- reference is null", HierarchySetting.ErrorShowReferenceIsNull); drawCheckBoxRight("- string is empty", HierarchySetting.ErrorShowStringIsEmpty); drawCheckBoxRight("- callback of event is missing (very slow)", HierarchySetting.ErrorShowMissingEventMethod); drawCheckBoxRight("- tag or layer is undefined", HierarchySetting.ErrorShowWhenTagOrLayerIsUndefined); HierarchySettings.getInstance().indentLevel -= 16; drawTextField("Ignore packages/classes", HierarchySetting.ErrorIgnoreString); drawSpace(1); } } private static void drawRendererComponentSettings() { if (drawComponentCheckBox("Renderer", HierarchySetting.RendererShow)) { Rect rect = getControlRect(0, 0); if (drawRestore()) { HierarchySettings.getInstance().restore(HierarchySetting.RendererShowDuringPlayMode); } drawBackground(rect.x, rect.y, rect.width, 18 + 5); drawSpace(4); drawCheckBoxRight("Show component during play mode", HierarchySetting.RendererShowDuringPlayMode); drawSpace(1); } } private static void drawPrefabComponentSettings() { if (drawComponentCheckBox("Prefab", HierarchySetting.PrefabShow)) { Rect rect = getControlRect(0, 0); if (drawRestore()) { HierarchySettings.getInstance().restore(HierarchySetting.PrefabShowBreakedPrefabsOnly); } drawBackground(rect.x, rect.y, rect.width, 18 + 5); drawSpace(4); drawCheckBoxRight("Show icon for broken prefabs only", HierarchySetting.PrefabShowBreakedPrefabsOnly); drawSpace(1); } } private static void drawTagLayerComponentSettings() { if (drawComponentCheckBox("Tag And Layer", HierarchySetting.TagAndLayerShow)) { Rect rect = getControlRect(0, 0); if (drawRestore()) { HierarchySettings.getInstance().restore(HierarchySetting.TagAndLayerShowDuringPlayMode); HierarchySettings.getInstance().restore(HierarchySetting.TagAndLayerSizeShowType); HierarchySettings.getInstance().restore(HierarchySetting.TagAndLayerType); HierarchySettings.getInstance().restore(HierarchySetting.TagAndLayerSizeValueType); HierarchySettings.getInstance().restore(HierarchySetting.TagAndLayerSizeValuePixel); HierarchySettings.getInstance().restore(HierarchySetting.TagAndLayerSizeValuePercent); HierarchySettings.getInstance().restore(HierarchySetting.TagAndLayerAligment); HierarchySettings.getInstance().restore(HierarchySetting.TagAndLayerLabelSize); HierarchySettings.getInstance().restore(HierarchySetting.TagAndLayerLabelAlpha); HierarchySettings.getInstance().restore(HierarchySetting.TagAndLayerTagLabelColor); HierarchySettings.getInstance().restore(HierarchySetting.TagAndLayerLayerLabelColor); } drawBackground(rect.x, rect.y, rect.width, 18 * 10 + 5); drawSpace(4); drawCheckBoxRight("Show component during play mode", HierarchySetting.TagAndLayerShowDuringPlayMode); drawEnum("Show", HierarchySetting.TagAndLayerSizeShowType, typeof(HierarchyTagAndLayerShowType)); drawEnum("Show tag and layer", HierarchySetting.TagAndLayerType, typeof(HierarchyTagAndLayerType)); HierarchyTagAndLayerSizeType newTagAndLayerSizeValueType = (HierarchyTagAndLayerSizeType)drawEnum("Unit of width", HierarchySetting.TagAndLayerSizeValueType, typeof(HierarchyTagAndLayerSizeType)); if (newTagAndLayerSizeValueType == HierarchyTagAndLayerSizeType.Pixel) drawIntSlider("Width in pixels", HierarchySetting.TagAndLayerSizeValuePixel, 5, 250); else drawFloatSlider("Percentage width", HierarchySetting.TagAndLayerSizeValuePercent, 0, 0.5f); drawEnum("Alignment", HierarchySetting.TagAndLayerAligment, typeof(HierarchyTagAndLayerAligment)); drawEnum("Label size", HierarchySetting.TagAndLayerLabelSize, typeof(HierarchyTagAndLayerLabelSize)); drawFloatSlider("Label alpha if default", HierarchySetting.TagAndLayerLabelAlpha, 0, 1.0f); drawColorPicker("Tag label color", HierarchySetting.TagAndLayerTagLabelColor); drawColorPicker("Layer label color", HierarchySetting.TagAndLayerLayerLabelColor); drawSpace(1); } } private static void drawColorComponentSettings() { if (drawComponentCheckBox("Color", HierarchySetting.ColorShow)) { Rect rect = getControlRect(0, 0); if (drawRestore()) { HierarchySettings.getInstance().restore(HierarchySetting.ColorShowDuringPlayMode); } drawBackground(rect.x, rect.y, rect.width, 18 + 5); drawSpace(4); drawCheckBoxRight("Show component during play mode", HierarchySetting.ColorShowDuringPlayMode); drawSpace(1); } } private static void drawGameObjectIconComponentSettings() { if (drawComponentCheckBox("GameObject Icon", HierarchySetting.GameObjectIconShow)) { Rect rect = getControlRect(0, 0); if (drawRestore()) { HierarchySettings.getInstance().restore(HierarchySetting.GameObjectIconShowDuringPlayMode); HierarchySettings.getInstance().restore(HierarchySetting.GameObjectIconSize); } drawBackground(rect.x, rect.y, rect.width, 18 * 2 + 5); drawSpace(4); drawCheckBoxRight("Show component during play mode", HierarchySetting.GameObjectIconShowDuringPlayMode); drawEnum("Icon size", HierarchySetting.GameObjectIconSize, typeof(HierarchySizeAll)); drawSpace(1); } } private static void drawTagIconComponentSettings() { if (drawComponentCheckBox("Tag Icon", HierarchySetting.TagIconShow)) { string[] tags = UnityEditorInternal.InternalEditorUtility.tags; bool showTagIconList = HierarchySettings.getInstance().get(HierarchySetting.TagIconListFoldout); Rect rect = getControlRect(0, 0); if (drawRestore()) { HierarchySettings.getInstance().restore(HierarchySetting.TagIconShowDuringPlayMode); HierarchySettings.getInstance().restore(HierarchySetting.TagIconSize); } drawBackground(rect.x, rect.y, rect.width, 18 * 3 + (showTagIconList ? 18 * tags.Length : 0) + 4 + 5); drawSpace(4); drawCheckBoxRight("Show component during play mode", HierarchySetting.TagIconShowDuringPlayMode); drawEnum("Icon size", HierarchySetting.TagIconSize, typeof(HierarchySizeAll)); if (drawFoldout("Tag icon list", HierarchySetting.TagIconListFoldout)) { List tagTextureList = TagTexture.loadTagTextureList(); bool changed = false; for (int i = 0; i < tags.Length; i++) { string tag = tags[i]; TagTexture tagTexture = tagTextureList.Find(t => t.tag == tag); Texture2D newTexture = (Texture2D)EditorGUI.ObjectField( getControlRect(0, 16, 34 + 16, 6), tag, tagTexture == null ? null : tagTexture.texture, typeof(Texture2D), false); if (newTexture != null && tagTexture == null) { TagTexture newTagTexture = new TagTexture(tag, newTexture); tagTextureList.Add(newTagTexture); changed = true; } else if (newTexture == null && tagTexture != null) { tagTextureList.Remove(tagTexture); changed = true; } else if (tagTexture != null && tagTexture.texture != newTexture) { tagTexture.texture = newTexture; changed = true; } drawSpace(i == tags.Length - 1 ? 2 : 2); } if (changed) { TagTexture.saveTagTextureList(HierarchySetting.TagIconList, tagTextureList); EditorApplication.RepaintHierarchyWindow(); } } drawSpace(1); } } private static void drawLayerIconComponentSettings() { if (drawComponentCheckBox("Layer Icon", HierarchySetting.LayerIconShow)) { string[] layers = UnityEditorInternal.InternalEditorUtility.layers; bool showLayerIconList = HierarchySettings.getInstance().get(HierarchySetting.LayerIconListFoldout); Rect rect = getControlRect(0, 0); if (drawRestore()) { HierarchySettings.getInstance().restore(HierarchySetting.LayerIconShowDuringPlayMode); HierarchySettings.getInstance().restore(HierarchySetting.LayerIconSize); } drawBackground(rect.x, rect.y, rect.width, 18 * 3 + (showLayerIconList ? 18 * layers.Length : 0) + 4 + 5); drawSpace(4); drawCheckBoxRight("Show component during play mode", HierarchySetting.LayerIconShowDuringPlayMode); drawEnum("Icon size", HierarchySetting.LayerIconSize, typeof(HierarchySizeAll)); if (drawFoldout("Layer icon list", HierarchySetting.LayerIconListFoldout)) { List layerTextureList = LayerTexture.loadLayerTextureList(); bool changed = false; for (int i = 0; i < layers.Length; i++) { string layer = layers[i]; LayerTexture layerTexture = layerTextureList.Find(t => t.layer == layer); Texture2D newTexture = (Texture2D)EditorGUI.ObjectField( getControlRect(0, 16, 34 + 16, 6), layer, layerTexture == null ? null : layerTexture.texture, typeof(Texture2D), false); if (newTexture != null && layerTexture == null) { LayerTexture newLayerTexture = new LayerTexture(layer, newTexture); layerTextureList.Add(newLayerTexture); changed = true; } else if (newTexture == null && layerTexture != null) { layerTextureList.Remove(layerTexture); changed = true; } else if (layerTexture != null && layerTexture.texture != newTexture) { layerTexture.texture = newTexture; changed = true; } drawSpace(i == layers.Length - 1 ? 2 : 2); } if (changed) { LayerTexture.saveLayerTextureList(HierarchySetting.LayerIconList, layerTextureList); EditorApplication.RepaintHierarchyWindow(); } } drawSpace(1); } } private static void drawChildrenCountComponentSettings() { if (drawComponentCheckBox("Children Count", HierarchySetting.ChildrenCountShow)) { Rect rect = getControlRect(0, 0); if (drawRestore()) { HierarchySettings.getInstance().restore(HierarchySetting.ChildrenCountShowDuringPlayMode); HierarchySettings.getInstance().restore(HierarchySetting.ChildrenCountLabelSize); HierarchySettings.getInstance().restore(HierarchySetting.ChildrenCountLabelColor); } drawBackground(rect.x, rect.y, rect.width, 18 * 3 + 5); drawSpace(4); drawCheckBoxRight("Show component during play mode", HierarchySetting.ChildrenCountShowDuringPlayMode); drawEnum("Label size", HierarchySetting.ChildrenCountLabelSize, typeof(HierarchySize)); drawColorPicker("Label color", HierarchySetting.ChildrenCountLabelColor); drawSpace(1); } } private static void drawVerticesAndTrianglesCountComponentSettings() { if (drawComponentCheckBox("Vertices And Triangles Count", HierarchySetting.VerticesAndTrianglesShow)) { Rect rect = getControlRect(0, 0); if (drawRestore()) { HierarchySettings.getInstance() .restore(HierarchySetting.VerticesAndTrianglesShowDuringPlayMode); HierarchySettings.getInstance().restore(HierarchySetting.VerticesAndTrianglesShowVertices); HierarchySettings.getInstance().restore(HierarchySetting.VerticesAndTrianglesShowTriangles); HierarchySettings.getInstance() .restore(HierarchySetting.VerticesAndTrianglesCalculateTotalCount); HierarchySettings.getInstance().restore(HierarchySetting.VerticesAndTrianglesLabelSize); HierarchySettings.getInstance() .restore(HierarchySetting.VerticesAndTrianglesVerticesLabelColor); HierarchySettings.getInstance() .restore(HierarchySetting.VerticesAndTrianglesTrianglesLabelColor); } drawBackground(rect.x, rect.y, rect.width, 18 * 7 + 5); drawSpace(4); drawCheckBoxRight("Show component during play mode", HierarchySetting.VerticesAndTrianglesShowDuringPlayMode); if (drawCheckBoxRight("Show vertices count", HierarchySetting.VerticesAndTrianglesShowVertices)) { if (HierarchySettings.getInstance() .get(HierarchySetting.VerticesAndTrianglesShowVertices) == false && HierarchySettings.getInstance() .get(HierarchySetting.VerticesAndTrianglesShowTriangles) == false) HierarchySettings.getInstance() .set(HierarchySetting.VerticesAndTrianglesShowTriangles, true); } if (drawCheckBoxRight("Show triangles count (very slow)", HierarchySetting.VerticesAndTrianglesShowTriangles)) { if (HierarchySettings.getInstance() .get(HierarchySetting.VerticesAndTrianglesShowVertices) == false && HierarchySettings.getInstance() .get(HierarchySetting.VerticesAndTrianglesShowTriangles) == false) HierarchySettings.getInstance() .set(HierarchySetting.VerticesAndTrianglesShowVertices, true); } drawCheckBoxRight("Calculate the count including children (very slow)", HierarchySetting.VerticesAndTrianglesCalculateTotalCount); drawEnum("Label size", HierarchySetting.VerticesAndTrianglesLabelSize, typeof(HierarchySize)); drawColorPicker("Vertices label color", HierarchySetting.VerticesAndTrianglesVerticesLabelColor); drawColorPicker("Triangles label color", HierarchySetting.VerticesAndTrianglesTrianglesLabelColor); drawSpace(1); } } private static void drawComponentsComponentSettings() { if (drawComponentCheckBox("Components", HierarchySetting.ComponentsShow)) { Rect rect = getControlRect(0, 0); if (drawRestore()) { HierarchySettings.getInstance().restore(HierarchySetting.ComponentsShowDuringPlayMode); HierarchySettings.getInstance().restore(HierarchySetting.ComponentsIconSize); } drawBackground(rect.x, rect.y, rect.width, 18 * 3 + 6); drawSpace(4); drawCheckBoxRight("Show component during play mode", HierarchySetting.ComponentsShowDuringPlayMode); drawEnum("Icon size", HierarchySetting.ComponentsIconSize, typeof(HierarchySizeAll)); drawTextField("Ignore packages/classes", HierarchySetting.ComponentsIgnore); drawSpace(2); } } // COMPONENTS ORDER private static void drawOrderSettings(Rect position, EditorWindow window) { if (drawRestore()) { HierarchySettings.getInstance().restore(HierarchySetting.ComponentsOrder); } HierarchySettings.getInstance().indentLevel += 4; string componentOrder = HierarchySettings.getInstance().get(HierarchySetting.ComponentsOrder); string[] componentIds = componentOrder.Split(';'); Rect rect = getControlRect(position.width, 17 * componentIds.Length + 10, 0, 0); if (HierarchySettings.getInstance().componentsOrderList == null) HierarchySettings.getInstance().componentsOrderList = new HierarchyComponentsOrderList(window); HierarchySettings.getInstance().componentsOrderList.draw(rect, componentIds); HierarchySettings.getInstance().indentLevel -= 4; } // ADDITIONAL SETTINGS private static void drawAdditionalSettings() { if (drawRestore()) { HierarchySettings.getInstance().restore(HierarchySetting.AdditionalShowHiddenQHierarchyObjectList); HierarchySettings.getInstance().restore(HierarchySetting.AdditionalHideIconsIfNotFit); HierarchySettings.getInstance().restore(HierarchySetting.AdditionalIdentation); HierarchySettings.getInstance().restore(HierarchySetting.AdditionalShowModifierWarning); HierarchySettings.getInstance().restore(HierarchySetting.AdditionalBackgroundColor); HierarchySettings.getInstance().restore(HierarchySetting.AdditionalActiveColor); HierarchySettings.getInstance().restore(HierarchySetting.AdditionalInactiveColor); HierarchySettings.getInstance().restore(HierarchySetting.AdditionalSpecialColor); } drawSpace(4); drawCheckBoxRight("Show QHierarchyObjectList GameObject", HierarchySetting.AdditionalShowHiddenQHierarchyObjectList); drawCheckBoxRight("Hide icons if not fit", HierarchySetting.AdditionalHideIconsIfNotFit); drawIntSlider("Right indent", HierarchySetting.AdditionalIdentation, 0, 500); drawCheckBoxRight("Show warning when using modifiers + click", HierarchySetting.AdditionalShowModifierWarning); drawColorPicker("Background color", HierarchySetting.AdditionalBackgroundColor); drawColorPicker("Active color", HierarchySetting.AdditionalActiveColor); drawColorPicker("Inactive color", HierarchySetting.AdditionalInactiveColor); drawColorPicker("Special color", HierarchySetting.AdditionalSpecialColor); drawSpace(1); } // PRIVATE private static void drawSection(string title) { Rect rect = getControlRect(0, 24, -3, 0); rect.width *= 2; rect.x = 0; GUI.Box(rect, ""); drawLeftLine(rect.y, rect.y + 24, HierarchySettings.getInstance().yellowColor); rect.x = HierarchySettings.getInstance().lastRect.x + 8; rect.y += 4; EditorGUI.LabelField(rect, title); } private static void drawSeparator(int spaceBefore = 0, int spaceAfter = 0, int height = 1) { if (spaceBefore > 0) drawSpace(spaceBefore); Rect rect = getControlRect(0, height, 0, 0); rect.width += 8; EditorGUI.DrawRect(rect, HierarchySettings.getInstance().separatorColor); if (spaceAfter > 0) drawSpace(spaceAfter); } private static bool drawComponentCheckBox(string label, HierarchySetting setting) { HierarchySettings.getInstance().indentLevel += 8; Rect rect = getControlRect(0, 28, 0, 0); float rectWidth = rect.width; bool isChecked = HierarchySettings.getInstance().get(setting); rect.x -= 1; rect.y += 7; rect.width = 14; rect.height = 14; if (GUI.Button(rect, isChecked ? HierarchySettings.getInstance().checkBoxChecked : HierarchySettings.getInstance().checkBoxUnchecked, GUIStyle.none)) { HierarchySettings.getInstance().set(setting, !isChecked); } rect.x += 14 + 10; rect.width = rectWidth - 14 - 8; rect.y -= (EditorGUIUtility.singleLineHeight - rect.height) * 0.5f; rect.height = EditorGUIUtility.singleLineHeight; EditorGUI.LabelField(rect, label); HierarchySettings.getInstance().indentLevel -= 8; return isChecked; } private static bool drawCheckBoxRight(string label, HierarchySetting setting) { Rect rect = getControlRect(0, 18, 34, 6); bool result = false; bool isChecked = HierarchySettings.getInstance().get(setting); float tempX = rect.x; rect.x += rect.width - 14; rect.y += 1; rect.width = 14; rect.height = 14; if (GUI.Button(rect, isChecked ? HierarchySettings.getInstance().checkBoxChecked : HierarchySettings.getInstance().checkBoxUnchecked, GUIStyle.none)) { HierarchySettings.getInstance().set(setting, !isChecked); result = true; } rect.width = rect.x - tempX - 4; rect.x = tempX; rect.y -= (EditorGUIUtility.singleLineHeight - rect.height) * 0.5f; rect.height = EditorGUIUtility.singleLineHeight; EditorGUI.LabelField(rect, label); return result; } private static void drawSpace(int value) { getControlRect(0, value, 0, 0); } private static void drawBackground(float x, float y, float width, float height) { EditorGUI.DrawRect(new Rect(x, y, width, height), HierarchySettings.getInstance().separatorColor); } private static void drawLeftLine(float fromY, float toY, Color color, float width = 0) { EditorGUI.DrawRect( new Rect(0, fromY, width == 0 ? HierarchySettings.getInstance().indentLevel : width, toY - fromY), color); } private static Rect getControlRect(float width, float height, float addIndent = 0, float remWidth = 0) { EditorGUILayout.GetControlRect(false, height, GUIStyle.none, GUILayout.ExpandWidth(true)); Rect rect = new Rect(HierarchySettings.getInstance().indentLevel + addIndent, HierarchySettings.getInstance().lastRect.y + HierarchySettings.getInstance().lastRect.height, (width == 0 ? HierarchySettings.getInstance().totalWidth - HierarchySettings.getInstance().indentLevel - addIndent - remWidth : width), height); HierarchySettings.getInstance().lastRect = rect; return rect; } private static bool drawRestore() { if (GUI.Button( new Rect( HierarchySettings.getInstance().lastRect.x + HierarchySettings.getInstance().lastRect.width - 16 - 5, HierarchySettings.getInstance().lastRect.y - 20, 16, 16), HierarchySettings.getInstance().restoreButtonTexture, GUIStyle.none)) { if (EditorUtility.DisplayDialog("Restore", "Restore default settings?", "Ok", "Cancel")) { return true; } } return false; } // GUI COMPONENTS private static void drawLabel(string label) { Rect rect = getControlRect(0, 16, 34, 6); rect.y -= (EditorGUIUtility.singleLineHeight - rect.height) * 0.5f; EditorGUI.LabelField(rect, label); drawSpace(2); } private static void drawTextField(string label, HierarchySetting setting) { string currentValue = HierarchySettings.getInstance().get(setting); string newValue = EditorGUI.TextField(getControlRect(0, 16, 34, 6), label, currentValue); if (!currentValue.Equals(newValue)) HierarchySettings.getInstance().set(setting, newValue); drawSpace(2); } private static bool drawFoldout(string label, HierarchySetting setting) { #if UNITY_2019_1_OR_NEWER Rect foldoutRect = getControlRect(0, 16, 19, 6); #else Rect foldoutRect = getControlRect(0, 16, 22, 6); #endif bool foldoutValue = HierarchySettings.getInstance().get(setting); bool newFoldoutValue = EditorGUI.Foldout(foldoutRect, foldoutValue, label); if (foldoutValue != newFoldoutValue) HierarchySettings.getInstance().set(setting, newFoldoutValue); drawSpace(2); return newFoldoutValue; } private static void drawColorPicker(string label, HierarchySetting setting) { Color currentColor = HierarchySettings.getInstance().getColor(setting); Color newColor = EditorGUI.ColorField(getControlRect(0, 16, 34, 6), label, currentColor); if (!currentColor.Equals(newColor)) HierarchySettings.getInstance().setColor(setting, newColor); drawSpace(2); } private static Enum drawEnum(string label, HierarchySetting setting, Type enumType) { Enum currentEnum = (Enum)Enum.ToObject(enumType, HierarchySettings.getInstance().get(setting)); Enum newEnumValue; if (!(newEnumValue = EditorGUI.EnumPopup(getControlRect(0, 16, 34, 6), label, currentEnum)) .Equals(currentEnum)) HierarchySettings.getInstance().set(setting, (int)(object)newEnumValue); drawSpace(2); return newEnumValue; } private static void drawIntSlider(string label, HierarchySetting setting, int minValue, int maxValue) { Rect rect = getControlRect(0, 16, 34, 4); int currentValue = HierarchySettings.getInstance().get(setting); int newValue = EditorGUI.IntSlider(rect, label, currentValue, minValue, maxValue); if (currentValue != newValue) HierarchySettings.getInstance().set(setting, newValue); drawSpace(2); } private static void drawFloatSlider(string label, HierarchySetting setting, float minValue, float maxValue) { Rect rect = getControlRect(0, 16, 34, 4); float currentValue = HierarchySettings.getInstance().get(setting); float newValue = EditorGUI.Slider(rect, label, currentValue, minValue, maxValue); if (currentValue != newValue) HierarchySettings.getInstance().set(setting, newValue); drawSpace(2); } } } ================================================ FILE: VirtueSky/ControlPanel/CPHierarchyDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: fa1ae88aaebf4b16a758d736c4b85d81 timeCreated: 1705920622 ================================================ FILE: VirtueSky/ControlPanel/CPIapDrawer.cs ================================================ using UnityEditor; using UnityEngine; #if VIRTUESKY_IAP using VirtueSky.Iap; #endif using VirtueSky.UtilsEditor; namespace VirtueSky.ControlPanel.Editor { public static class CPIapDrawer { #if VIRTUESKY_IAP private static IapSetting _iapSetting; #endif private static UnityEditor.Editor _editor; private static Vector2 scroll = Vector2.zero; public static void OnEnable() { Init(); } private static void Init() { if (_editor != null) { _editor = null; } #if VIRTUESKY_IAP _iapSetting = CreateAsset.GetScriptableAsset(); _editor = UnityEditor.Editor.CreateEditor(_iapSetting); #endif } public static void OnDrawIap(Rect position) { GUILayout.Space(10); GUILayout.BeginVertical(); CPUtility.DrawHeaderIcon(StatePanelControl.InAppPurchase, "In App Purchase"); GUILayout.Space(10); scroll = EditorGUILayout.BeginScrollView(scroll); #if VIRTUESKY_IAP if (_iapSetting == null) { if (GUILayout.Button("Create IAP Setting")) { _iapSetting = CreateAsset.CreateAndGetScriptableAsset("/Iap/Setting", isPingAsset: false); Init(); } } else { if (_editor == null) { EditorGUILayout.HelpBox("Couldn't create the settings resources editor.", MessageType.Error); return; } else { _editor.OnInspectorGUI(); } } #else EditorGUILayout.HelpBox( $"Add scripting define symbols \"{ConstantDefineSymbols.VIRTUESKY_IAP}\" to use IAP", MessageType.Warning); #endif GUILayout.Space(10); CPUtility.GuiLine(2); GUILayout.Space(10); CPUtility.DrawHeader("Install Sdk"); GUILayout.Space(10); CPUtility.DrawButtonInstallPackage("Install In App Purchasing", "Remove In App Purchasing", ConstantPackage.PackageNameInAppPurchase, ConstantPackage.MaxVersionInAppPurchase); GUILayout.Space(10); CPUtility.GuiLine(2); GUILayout.Space(10); CPUtility.DrawHeader("Define Symbols"); GUILayout.Space(10); #if !VIRTUESKY_IAP EditorGUILayout.HelpBox( $"Add scripting define symbols \"{ConstantDefineSymbols.VIRTUESKY_IAP}\" to use IAP", MessageType.Info); #endif CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_IAP); #if VIRTUESKY_IAP GUILayout.Space(10); CPUtility.GuiLine(2); GUILayout.Space(10); GUILayout.Label("Ping Iap Settings", EditorStyles.boldLabel); GUILayout.Space(10); if (GUILayout.Button("Ping")) { if (_iapSetting == null) { Debug.LogError("IapSetting have not been created yet"); } else { EditorGUIUtility.PingObject(_iapSetting); Selection.activeObject = _iapSetting; } } #endif GUILayout.Space(10); EditorGUILayout.EndScrollView(); GUILayout.EndVertical(); } } } ================================================ FILE: VirtueSky/ControlPanel/CPIapDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: 70419656f8c04e408772abf5d2e24ad2 timeCreated: 1704943160 ================================================ FILE: VirtueSky/ControlPanel/CPInAppReviewDrawer.cs ================================================ using UnityEditor; using UnityEngine; using VirtueSky.Misc; using VirtueSky.Rating; using VirtueSky.UtilsEditor; namespace VirtueSky.ControlPanel.Editor { public static class CPInAppReviewDrawer { public static void OnDrawInAppReview(Rect position) { GUILayout.Space(10); GUILayout.BeginVertical(); CPUtility.DrawHeaderIcon(StatePanelControl.InAppReview, "In App Review"); GUILayout.Space(10); if (GUILayout.Button("Create Scriptable In App Review")) { RatingWindowEditor.CreateInAppReview(); } GUILayout.Space(10); CPUtility.DrawLineLastRectY(3, ConstantControlPanel.POSITION_X_START_CONTENT, position.width); GUILayout.Space(10); CPUtility.DrawHeader("Install Sdk"); GUILayout.Space(10); CPUtility.DrawButtonInstallPackage("Install Google Play Review", "Remove Google Play Review", ConstantPackage.PackageNameGGPlayReview, ConstantPackage.MaxVersionGGPlayReview); CPUtility.DrawButtonInstallPackage("Install Google Play Core", "Remove Google Play Core", ConstantPackage.PackageNameGGPlayCore, ConstantPackage.MaxVersionGGPlayCore); CPUtility.DrawButtonInstallPackage("Install Google Play Common", "Remove Google Play Common", ConstantPackage.PackageNameGGPlayCommon, ConstantPackage.MaxVersionGGPlayCommon); CPUtility.DrawButtonInstallPackage("Install Google External Dependency Manager", "Remove Google External Dependency Manager", ConstantPackage.PackageNameGGExternalDependencyManager, ConstantPackage.MaxVersionGGExternalDependencyManager); GUILayout.Space(10); CPUtility.DrawLineLastRectY(3, ConstantControlPanel.POSITION_X_START_CONTENT, position.width); GUILayout.Space(10); CPUtility.DrawHeader("Define symbols"); GUILayout.Space(10); #if !VIRTUESKY_RATING EditorGUILayout.HelpBox( "Add scripting define symbols \"VIRTUESKY_RATING\" to use In App Review", MessageType.Info); #endif CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_RATING); GUILayout.EndVertical(); } } } ================================================ FILE: VirtueSky/ControlPanel/CPInAppReviewDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: 5f12bee3b37b49d2b42c61c57f79c05e timeCreated: 1704943618 ================================================ FILE: VirtueSky/ControlPanel/CPLevelEditorDrawer.cs ================================================ using System; using System.Collections.Generic; using System.IO; using System.Linq; using UnityEditor; using UnityEditor.SceneManagement; using UnityEngine; using VirtueSky.LevelEditor; using VirtueSky.Misc; using VirtueSky.UtilsEditor; namespace VirtueSky.ControlPanel.Editor { public static class CPLevelEditorDrawer { private static LevelEditorTabType levelEditorTabType = LevelEditorTabType.Setting; public static void OnDrawLevelEditor(Rect position) { GUILayout.Space(10); GUILayout.BeginVertical(); CPUtility.DrawHeaderIcon(StatePanelControl.LevelEditor, "Level Editor"); GUILayout.Space(10); var scriptableSetting = Resources.Load(nameof(LevelSystemEditorSetting)); if (scriptableSetting == null) { GUI.enabled = !EditorApplication.isCompiling; if (GUILayout.Button("Setup Level Editor")) { var setting = ScriptableObject.CreateInstance(); const string path = "Assets/_Sunflower/Editor/Resources"; if (!Directory.Exists(path)) Directory.CreateDirectory(path); AssetDatabase.CreateAsset(setting, $"{path}/{nameof(LevelSystemEditorSetting)}.asset"); RegistryManager.Add("com.unity.addressables", "1.21.21"); RegistryManager.Resolve(); AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); Debug.Log( $"{nameof(LevelSystemEditorSetting)} was created ad {path}/{nameof(LevelSystemEditorSetting)}.asset"); } GUI.enabled = true; } else { if (scriptableSetting.PickObjects.Count == 0) RefreshAll(); DrawTab(); GUILayout.Space(10); CPUtility.GuiLine(2); GUILayout.Space(10); DrawContent(position); } GUILayout.EndVertical(); } static void DrawTab() { EditorGUILayout.BeginHorizontal(); bool clickSetting = GUILayout.Toggle(levelEditorTabType == LevelEditorTabType.Setting, "Setting", GUI.skin.button, GUILayout.ExpandWidth(true), GUILayout.Height(25)); if (clickSetting && levelEditorTabType != LevelEditorTabType.Setting) { levelEditorTabType = LevelEditorTabType.Setting; } bool clickPickup = GUILayout.Toggle(levelEditorTabType == LevelEditorTabType.Pickup, "Pickup Area", GUI.skin.button, GUILayout.ExpandWidth(true), GUILayout.Height(25)); if (clickPickup && levelEditorTabType != LevelEditorTabType.Pickup) { levelEditorTabType = LevelEditorTabType.Pickup; RefreshAll(); } EditorGUILayout.EndHorizontal(); } #region preview generator private static PreviewGenerator previewGenerator; private static PreviewGenerator PreviewGenerator { get { var generator = previewGenerator; if (generator != null) return generator; return previewGenerator = new PreviewGenerator { width = 512, height = 512, transparentBackground = true, sizingType = PreviewGenerator.ImageSizeType.Fit }; } } private static Dictionary previewDict; public static void ClearPreviews() { if (previewDict != null) { foreach (var kvp in previewDict.ToList()) { previewDict[kvp.Key] = null; } previewDict.Clear(); } } public static void ClearPreview(GameObject go) { if (previewDict != null) { foreach (var kvp in previewDict.ToList()) { previewDict[kvp.Key] = null; } previewDict.Clear(); } } public static Texture2D GetPreview(GameObject go, bool canCreate = true) { if (!go) return null; previewDict ??= new Dictionary(); previewDict.TryGetValue(go, out var tex); if (!canCreate) return tex != null ? tex : default; if (tex) return tex; tex = PreviewGenerator.CreatePreview(go.gameObject); previewDict[go] = tex; return tex; } #endregion private static Vector2 EventMousePoint { get { var position = Event.current.mousePosition; position.y = Screen.height - position.y - 60f; return position; } } private static List PickObjects => LevelSystemEditorSetting.Instance.PickObjects ??= new List(); public static void OnEnable() { if (!LevelSystemEditorSetting.IsExist()) return; RefreshPickObject(); SceneView.duringSceneGui += OnSceneGUI; } public static void OnDisable() { SceneView.duringSceneGui -= OnSceneGUI; } private static void OnProjectChange() { TryClose(); } private static void OnHierarchyChange() { TryClose(); } private static bool TryClose() { return false; } // ReSharper disable once UnusedMember.Local private static void RefreshAll() { ClearPreviews(); RefreshPickObject(); // ClearEditor(window); } /// /// display picked object in editor /// private static void RefreshPickObject() { LevelSystemEditorSetting.Instance.PickObjects = new List(); var blacklistAssets = new List(); var whitelistAssets = new List(); if (!LevelSystemEditorSetting.Instance.blacklistPaths.IsNullOrEmpty()) { blacklistAssets = AssetDatabase.FindAssets("t:GameObject", LevelSystemEditorSetting.Instance.blacklistPaths.ToArray()) .Select(AssetDatabase.GUIDToAssetPath) .Select(AssetDatabase.LoadAssetAtPath) .ToList(); foreach (string blacklistPath in LevelSystemEditorSetting.Instance.blacklistPaths) { if (File.Exists(blacklistPath)) blacklistAssets.Add( AssetDatabase.LoadAssetAtPath(blacklistPath)); } } if (!LevelSystemEditorSetting.Instance.whitelistPaths.IsNullOrEmpty()) { whitelistAssets = AssetDatabase.FindAssets("t:GameObject", LevelSystemEditorSetting.Instance.whitelistPaths.ToArray()) .Select(AssetDatabase.GUIDToAssetPath) .Select(AssetDatabase.LoadAssetAtPath) .ToList(); foreach (string whitelistPath in LevelSystemEditorSetting.Instance.whitelistPaths) { if (File.Exists(whitelistPath)) whitelistAssets.Add( AssetDatabase.LoadAssetAtPath(whitelistPath)); } } var resultAssets = whitelistAssets.Where(_ => !blacklistAssets.Contains(_)); foreach (var o in resultAssets) { string group = Path.GetDirectoryName(AssetDatabase.GetAssetPath(o)) ?.Replace('\\', '/').Split('/').Last(); var po = new PickObject { pickedObject = o.gameObject, group = group }; LevelSystemEditorSetting.Instance.PickObjects.Add(po); } } private static bool CheckEscape() { if (Event.current.type == EventType.KeyDown && Event.current.keyCode == KeyCode.Escape) { LevelSystemEditorSetting.Instance.CurrentPickObject = null; // window.Repaint(); SceneView.RepaintAll(); return true; } return false; } private static void DrawContent(Rect position) { if (TryClose()) return; if (CheckEscape()) return; SceneView.RepaintAll(); if (levelEditorTabType == LevelEditorTabType.Setting) { InternalDrawSettingTab(position); } else { InternalDrawPickupArea(position); } } private static void InternalDrawSettingTab(Rect position) { GUILayout.BeginVertical(); LevelSystemEditorSetting.Instance.SettingTabScrollPosition = GUILayout.BeginScrollView(LevelSystemEditorSetting.Instance.SettingTabScrollPosition); InternalDrawDropArea(position); GUILayout.Space(4); InternalDrawSetting(); GUILayout.EndScrollView(); GUILayout.EndVertical(); } private static void InternalDrawDropArea(Rect position) { Uniform.DrawGroupFoldout("level_editor_drop_area", "Drop Area", DrawDropArea); void DrawDropArea() { GUILayout.Space(2); float width = 0; var @event = Event.current; #region horizontal EditorGUILayout.BeginHorizontal(); float widthArea = (float)(position.width - ConstantControlPanel.POSITION_X_START_CONTENT) / 2 - 5; var whiteArea = GUILayoutUtility.GetRect(widthArea, 50f, GUILayout.ExpandWidth(true)); var blackArea = GUILayoutUtility.GetRect(widthArea, 50f, GUILayout.ExpandWidth(true)); // ReSharper disable once CompareOfFloatsByEqualityOperator if (whiteArea.width == 1f) width = widthArea; else width = whiteArea.width; GUI.backgroundColor = new Color(0f, 0.83f, 1f); GUI.Box(whiteArea, "[WHITE LIST]", new GUIStyle(EditorStyles.helpBox) { alignment = TextAnchor.MiddleCenter, fontStyle = FontStyle.Italic }); GUI.backgroundColor = Color.white; GUI.backgroundColor = new Color(1f, 0.13f, 0f); GUI.Box(blackArea, "[BLACK LIST]", new GUIStyle(EditorStyles.helpBox) { alignment = TextAnchor.MiddleCenter, fontStyle = FontStyle.Italic }); GUI.backgroundColor = Color.white; switch (@event.type) { case EventType.DragUpdated: case EventType.DragPerform: if (whiteArea.Contains(@event.mousePosition)) { DragAndDrop.visualMode = DragAndDropVisualMode.Copy; if (@event.type == EventType.DragPerform) { DragAndDrop.AcceptDrag(); foreach (string path in DragAndDrop.paths) { if (File.Exists(path)) { var r = AssetDatabase.LoadAssetAtPath( path); if (r.GetType() != typeof(GameObject)) continue; } ValidateWhitelist(path, ref LevelSystemEditorSetting.Instance.blacklistPaths); AddToWhitelist(path); } ReduceScopeDirectory(ref LevelSystemEditorSetting.Instance .whitelistPaths); RefreshAll(); } } else if (blackArea.Contains(@event.mousePosition)) { DragAndDrop.visualMode = DragAndDropVisualMode.Copy; if (@event.type == EventType.DragPerform) { DragAndDrop.AcceptDrag(); foreach (string path in DragAndDrop.paths) { if (File.Exists(path)) { var r = AssetDatabase.LoadAssetAtPath( path); if (r.GetType() != typeof(GameObject)) continue; } ValidateBlacklist(path, ref LevelSystemEditorSetting.Instance.whitelistPaths); AddToBlacklist(path); } ReduceScopeDirectory(ref LevelSystemEditorSetting.Instance .blacklistPaths); RefreshAll(); } } break; case EventType.MouseDown when @event.button == 1: var menu = new GenericMenu(); if (whiteArea.Contains(@event.mousePosition)) { menu.AddItem(new GUIContent("Clear All [WHITE LIST]"), false, () => { LevelSystemEditorSetting.Instance.whitelistPaths.Clear(); SaveLevelSystemSetting(); RefreshAll(); }); } else if (blackArea.Contains(@event.mousePosition)) { menu.AddItem(new GUIContent("Clear All [BLACK LIST]"), false, () => { LevelSystemEditorSetting.Instance.blacklistPaths.Clear(); SaveLevelSystemSetting(); RefreshAll(); }); } menu.ShowAsContext(); break; } EditorGUILayout.EndHorizontal(); #endregion #region horizontal EditorGUILayout.BeginHorizontal(); #region vertical scope using (var scope = new EditorGUILayout.VerticalScope(GUILayout.Width(width - 10))) { if (LevelSystemEditorSetting.Instance.whitelistPaths.Count == 0) { EditorGUILayout.LabelField(new GUIContent(""), GUILayout.Width(width - 50), GUILayout.Height(0)); } else { GUILayout.Space(2); LevelSystemEditorSetting.Instance.WhitelistScrollPosition = GUILayout.BeginScrollView( LevelSystemEditorSetting.Instance.WhitelistScrollPosition, false, false, GUILayout.Height(250)); foreach (string t in LevelSystemEditorSetting.Instance.whitelistPaths .ToList()) { DrawRow(t, width, _ => { LevelSystemEditorSetting.Instance.whitelistPaths.Remove(_); SaveLevelSystemSetting(); }); } GUILayout.EndScrollView(); } } #endregion GUILayout.Space(4); #region vertical scope using (var scope = new EditorGUILayout.VerticalScope(GUILayout.Width(width - 15))) { if (LevelSystemEditorSetting.Instance.blacklistPaths.Count == 0) { EditorGUILayout.LabelField(new GUIContent(""), GUILayout.Width(width - 50), GUILayout.Height(0)); } else { GUILayout.Space(2); LevelSystemEditorSetting.Instance.BlacklistScrollPosition = GUILayout.BeginScrollView( LevelSystemEditorSetting.Instance.BlacklistScrollPosition, false, false, GUILayout.Height(250)); foreach (string t in LevelSystemEditorSetting.Instance.blacklistPaths .ToList()) { DrawRow(t, width, _ => { LevelSystemEditorSetting.Instance.blacklistPaths.Remove(_); SaveLevelSystemSetting(); }); } GUILayout.EndScrollView(); } } #endregion EditorGUILayout.EndHorizontal(); #endregion } void DrawRow(string content, float width, Action action) { #region horizontal EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField(new GUIContent(content), GUILayout.Width(width - 100)); GUILayout.FlexibleSpace(); if (GUILayout.Button(Uniform.IconContent("d_scenevis_visible_hover", "Ping Selection"))) { var obj = AssetDatabase.LoadAssetAtPath(content); Selection.activeObject = obj; EditorGUIUtility.PingObject(obj); } if (GUILayout.Button(Uniform.IconContent("Toolbar Minus", "Remove"))) { action?.Invoke(content); RefreshAll(); } EditorGUILayout.EndHorizontal(); #endregion } } private static void ValidateWhitelist(string path, ref List blackList) { foreach (string t in blackList.ToList()) { if (path.Equals(t)) blackList.Remove(t); } } private static void ValidateBlacklist(string path, ref List whiteList) { foreach (string t in whiteList.ToList()) { if (path.Equals(t) || IsChildOfPath(t, path)) whiteList.Remove(t); } } private static void AddToWhitelist(string path) { var check = false; foreach (string whitePath in LevelSystemEditorSetting.Instance.whitelistPaths) { if (IsChildOfPath(path, whitePath)) check = true; } if (!check) LevelSystemEditorSetting.Instance.whitelistPaths.Add(path); LevelSystemEditorSetting.Instance.whitelistPaths = LevelSystemEditorSetting.Instance .whitelistPaths.Distinct().ToList(); //unique SaveLevelSystemSetting(); } private static void AddToBlacklist(string path) { var check = false; foreach (string blackPath in LevelSystemEditorSetting.Instance.blacklistPaths) { if (IsChildOfPath(path, blackPath)) check = true; } if (!check) LevelSystemEditorSetting.Instance.blacklistPaths.Add(path); LevelSystemEditorSetting.Instance.blacklistPaths = LevelSystemEditorSetting.Instance .blacklistPaths.Distinct().ToList(); //unique SaveLevelSystemSetting(); } // return true if child is childrent of parent private static bool IsChildOfPath(string child, string parent) { if (child.Equals(parent)) return false; var allParent = new List(); GetAllParentDirectories(new DirectoryInfo(child), ref allParent); foreach (var p in allParent) { bool check = EqualPath(p, parent); if (check) return true; } return false; } private static void GetAllParentDirectories(DirectoryInfo directoryToScan, ref List directories) { while (true) { if (directoryToScan == null || directoryToScan.Name == directoryToScan.Root.Name || !directoryToScan.FullName.Contains("Assets")) return; directories.Add(directoryToScan); directoryToScan = directoryToScan.Parent; } } private static bool EqualPath(FileSystemInfo info, string str) { string relativePath = info.FullName; if (relativePath.StartsWith(Application.dataPath.Replace('/', '\\'))) relativePath = "Assets" + relativePath.Substring(Application.dataPath.Length); relativePath = relativePath.Replace('\\', '/'); return str.Equals(relativePath); } private static void ReduceScopeDirectory(ref List source) { var arr = new string[source.Count]; source.CopyTo(arr); var valueRemove = new List(); var unique = arr.Distinct().ToList(); foreach (string u in unique) { var check = false; foreach (string k in unique) { if (IsChildOfPath(u, k)) check = true; } if (check) valueRemove.Add(u); } foreach (string i in valueRemove) { unique.Remove(i); } source = unique; } private static void InternalDrawSetting() { Uniform.DrawGroupFoldout("level_editor_config", "Setting", DrawSetting); void DrawSetting() { LevelSystemEditorSetting.Instance.SelectedSpawn = EditorGUILayout.Popup("Where Spawn", LevelSystemEditorSetting.Instance.SelectedSpawn, LevelSystemEditorSetting.Instance.optionsSpawn); if (EditorGUI.EndChangeCheck()) { switch (LevelSystemEditorSetting.Instance .optionsSpawn[LevelSystemEditorSetting.Instance.SelectedSpawn].ToLower()) { case "default": break; case "index": var currentPrefabState = GetCurrentPrefabStage(); if (currentPrefabState != null) { LevelSystemEditorSetting.Instance.RootIndexSpawn = EditorGUILayout.IntField( new GUIContent("Index spawn", "Index from root stage contex"), LevelSystemEditorSetting.Instance.RootIndexSpawn); } else { EditorGUILayout.HelpBox("Index spawn only work in PrefabMode!", MessageType.Warning); } break; case "custom": LevelSystemEditorSetting.Instance.RootSpawn = (GameObject)EditorGUILayout.ObjectField( "Spawn in GO here -->", LevelSystemEditorSetting.Instance.RootSpawn, typeof(GameObject), true); break; } } LevelSystemEditorSetting.Instance.SelectedMode = EditorGUILayout.Popup("Mode", LevelSystemEditorSetting.Instance.SelectedMode, LevelSystemEditorSetting.Instance.optionsMode); if (EditorGUI.EndChangeCheck()) { switch (LevelSystemEditorSetting.Instance .optionsMode[LevelSystemEditorSetting.Instance.SelectedMode].ToLower()) { case "renderer": EditorGUILayout.HelpBox("Based on Renderer detection", MessageType.Info); break; case "ignore": EditorGUILayout.HelpBox( "GameObject will be spawn correcty at raycast location\nIgnore calculate bound object", MessageType.Info); break; } } } } private static void InternalDrawPickupArea(Rect position) { float height = 0f; Uniform.DrawGroupFoldoutWithRightClick("level_editor_pickup_area", "Pickup Area", DrawPickupArea, ShowMenuRefresh); void DrawPickupArea() { var tex = GetPreview(LevelSystemEditorSetting.Instance.CurrentPickObject ?.pickedObject); if (tex) { string pickObjectName = LevelSystemEditorSetting.Instance.CurrentPickObject?.pickedObject.name; #region horizontal EditorGUILayout.BeginHorizontal(); GUILayout.Space(position.width / 2 - 50); if (LevelSystemEditorSetting.Instance.EditorInspectorPreview == null || LevelSystemEditorSetting.Instance.PreviousObjectInspectorPreview != LevelSystemEditorSetting.Instance.CurrentPickObject?.pickedObject) { LevelSystemEditorSetting.Instance.EditorInspectorPreview = UnityEditor.Editor.CreateEditor(LevelSystemEditorSetting.Instance.CurrentPickObject ?.pickedObject); } var rect = GUILayoutUtility.GetLastRect(); LevelSystemEditorSetting.Instance.EditorInspectorPreview.DrawPreview(new Rect( new Vector2(position.width / 2 - 50, rect.position.y), new Vector2(100, 100))); LevelSystemEditorSetting.Instance.PreviousObjectInspectorPreview = LevelSystemEditorSetting.Instance.CurrentPickObject?.pickedObject; GUI.color = new Color(1, 1, 1, 0f); if (GUILayout.Button(tex, GUILayout.Height(80), GUILayout.Width(80))) { } GUI.color = Color.white; EditorGUILayout.EndHorizontal(); #endregion EditorGUILayout.LabelField( $"Selected: {pickObjectName}\nPress Icon Again Or Escape Key To Deselect", new GUIStyle(EditorStyles.label) { richText = true }, GUILayout.Height(40)); height -= 128; EditorGUILayout.HelpBox("Shift + Click To Add", MessageType.Info); } else { EditorGUILayout.HelpBox("Select An Object First", MessageType.Info); } height -= 100; if (Uniform.GetFoldoutState("level_editor_drop_area")) { if (LevelSystemEditorSetting.Instance.blacklistPaths.Count == 0 && LevelSystemEditorSetting.Instance.whitelistPaths.Count == 0) { height -= 94; } else { // height -= 342; } } else { height -= 33; } if (Uniform.GetFoldoutState("level_editor_config")) { switch (LevelSystemEditorSetting.Instance .optionsSpawn[LevelSystemEditorSetting.Instance.SelectedSpawn].ToLower()) { case "default": height -= 122; break; case "index": var currentPrefabState = GetCurrentPrefabStage(); if (currentPrefabState != null) { height -= 146; } else { height -= 162; } break; case "custom": height -= 146; break; } } else { height -= 33; } var h = position.height + height; LevelSystemEditorSetting.Instance.PickObjectScrollPosition = GUILayout.BeginScrollView(LevelSystemEditorSetting.Instance.PickObjectScrollPosition, GUILayout.Height(h)); var resultSplitGroupObjects = PickObjects.GroupBy(_ => _.group).Select(_ => _.ToList()).ToList(); foreach (var splitGroupObject in resultSplitGroupObjects) { string nameGroup = splitGroupObject[0].group.ToUpper(); Uniform.DrawGroupFoldout($"level_editor_pickup_area_child_{nameGroup}", nameGroup, () => DrawInGroup(splitGroupObject, position)); } GUILayout.EndScrollView(); } void DrawInGroup(IReadOnlyList pickObjectsInGroup, Rect position) { const int spacing = 25; var counter = 0; CalculateIdealCount(position.width - 50, 60, 135, spacing, 5, out int count, out float size); count = Mathf.Max(1, count); while (counter >= 0 && counter < pickObjectsInGroup.Count) { EditorGUILayout.BeginHorizontal(); GUILayout.Space(8); for (var x = 0; x < count; x++) { var pickObj = pickObjectsInGroup[counter]; var go = pickObj.pickedObject; var tex = GetPreview(go); if (pickObj == LevelSystemEditorSetting.Instance.CurrentPickObject) { GUI.color = new Color32(79, 213, 255, 255); } else { GUI.color = Color.white; } if (GUILayout.Button(new GUIContent(""), GUILayout.Width(size), GUILayout.Height(size))) { if (Event.current.button == 1) { ShowMenuRightClickItem(pickObj); } else { LevelSystemEditorSetting.Instance.CurrentPickObject = LevelSystemEditorSetting.Instance.CurrentPickObject == pickObj ? null : pickObj; } } Rect Grown(Rect r, Vector2 half) { return new Rect(r.position - half, r.size + half * 2); } GUI.color = Color.white; var rect = GUILayoutUtility.GetLastRect(); if (tex) GUI.DrawTexture(Grown(rect, Vector2.one * -10), tex, ScaleMode.ScaleToFit); if (go) { EditorGUI.LabelField(Grown(rect, new Vector2(0, 15)), go.name, new GUIStyle(EditorStyles.miniLabel) { alignment = TextAnchor.LowerCenter, }); } counter++; if (counter >= pickObjectsInGroup.Count) break; GUILayout.Space(4); } GUILayout.FlexibleSpace(); EditorGUILayout.EndHorizontal(); GUILayout.Space(spacing); } } void ShowMenuRefresh() { var menu = new GenericMenu(); menu.AddItem(new GUIContent("Refresh Pickup Area"), false, () => { LevelSystemEditorSetting.Instance.CurrentPickObject = null; RefreshAll(); }); menu.ShowAsContext(); } void ShowMenuRightClickItem(PickObject pickObj) { var menu = new GenericMenu(); menu.AddItem(new GUIContent("Ignore"), false, () => IgnorePath(pickObj)); menu.AddItem(new GUIContent("Ping"), false, () => { Selection.activeObject = pickObj.pickedObject; EditorGUIUtility.PingObject(pickObj.pickedObject); }); menu.ShowAsContext(); } void IgnorePath(PickObject pickObj) { var path = AssetDatabase.GetAssetPath(pickObj.pickedObject); ValidateBlacklist(path, ref LevelSystemEditorSetting.Instance.whitelistPaths); AddToBlacklist(path); ReduceScopeDirectory(ref LevelSystemEditorSetting.Instance.blacklistPaths); RefreshAll(); } } private static void SaveLevelSystemSetting() { EditorUtility.SetDirty(LevelSystemEditorSetting.Instance); AssetDatabase.SaveAssets(); } private static void OnSceneGUI(SceneView sceneView) { if (TryClose()) return; if (CheckEscape()) return; if (LevelSystemEditorSetting.Instance != null) { TryFakeRender(sceneView); } } private static void TryFakeRender(SceneView sceneView) { var e = Event.current; if (!e.shift) { if (LevelSystemEditorSetting.Instance.PreviewPickupObject != null) UnityEngine.Object.DestroyImmediate(LevelSystemEditorSetting.Instance.PreviewPickupObject); return; } if (LevelSystemEditorSetting.Instance.CurrentPickObject == null || !LevelSystemEditorSetting.Instance.CurrentPickObject.pickedObject) return; Vector3 mousePosition; Vector3 normal; if (sceneView.in2DMode) { bool state = EditorExtend.Get2DMouseScenePosition(out var mousePosition2d); mousePosition = mousePosition2d; if (!state) return; EditorExtend.FakeRenderSprite(LevelSystemEditorSetting.Instance.CurrentPickObject.pickedObject, mousePosition, Vector3.one, Quaternion.identity); SceneView.RepaintAll(); if (e.type == EventType.MouseDown && e.button == 0) { AddPickObject(LevelSystemEditorSetting.Instance.CurrentPickObject, mousePosition); EditorExtend.SkipEvent(); } } else { var pos = EditorExtend.GetInnerGuiPosition(sceneView); RaycastHit? raycastHit; if (pos.Contains(e.mousePosition)) { var currentPrefabState = GetCurrentPrefabStage(); if (currentPrefabState != null) { var (mouseCast, hitInfo) = RaycastPoint(GetParent(), EventMousePoint); mousePosition = mouseCast; normal = hitInfo.HasValue ? hitInfo.Value.normal : Vector3.up; raycastHit = hitInfo; } else { Probe.Pick(ProbeFilter.Default, sceneView, e.mousePosition, out mousePosition, out normal); raycastHit = null; } float discSize = HandleUtility.GetHandleSize(mousePosition) * 0.4f; Handles.color = new Color(1, 0, 0, 0.5f); Handles.DrawSolidDisc(mousePosition, normal, discSize * 0.5f); if (!LevelSystemEditorSetting.Instance.PreviewPickupObject) { LevelSystemEditorSetting.Instance.PreviewPickupObject = (GameObject)PrefabUtility.InstantiatePrefab(LevelSystemEditorSetting.Instance .CurrentPickObject ?.pickedObject); StageUtility.PlaceGameObjectInCurrentStage(LevelSystemEditorSetting.Instance .PreviewPickupObject); LevelSystemEditorSetting.Instance.PreviewPickupObject.hideFlags = HideFlags.HideAndDontSave; LevelSystemEditorSetting.Instance.PreviewPickupObject.layer = LayerMask.NameToLayer("Ignore Raycast"); } #pragma warning disable CS8321 void SetPosition2() { var rendererAttach = LevelSystemEditorSetting.Instance.CurrentPickObject?.pickedObject .GetComponentInChildren(); if (raycastHit == null || rendererAttach == null) return; var rendererOther = raycastHit.Value.collider.transform .GetComponentInChildren(); if (rendererOther == null) return; LevelSystemEditorSetting.Instance.PreviewPickupObject.transform.position = GetSpawnPosition( rendererAttach, rendererOther, raycastHit.Value); } #pragma warning restore CS8321 void SetPosition() { LevelSystemEditorSetting.Instance.PreviewPickupObject.transform.position = mousePosition; switch (LevelSystemEditorSetting.Instance .optionsMode[LevelSystemEditorSetting.Instance.SelectedMode].ToLower()) { case "renderer": if (LevelSystemEditorSetting.Instance.PreviewPickupObject.CalculateBounds( out var bounds, Space.World, true, false, false, false)) { float difference = 0; if (normal == Vector3.up || normal == Vector3.down) { difference = mousePosition.y - bounds.min.y; } else if (normal == Vector3.right || normal == Vector3.left) { difference = mousePosition.x - bounds.min.x; } else if (normal == Vector3.forward || normal == Vector3.back) { difference = mousePosition.z - bounds.min.z; } LevelSystemEditorSetting.Instance.PreviewPickupObject.transform.position += difference * normal; } break; case "ignore": break; } } SetPosition(); if (e.type == EventType.MouseDown && e.button == 0 && LevelSystemEditorSetting.Instance.PreviewPickupObject) { AddPickObject(LevelSystemEditorSetting.Instance.CurrentPickObject, LevelSystemEditorSetting.Instance.PreviewPickupObject.transform.position); EditorExtend.SkipEvent(); } } } } /// /// only use when determined root /// /// /// /// /// private static (bool, RaycastHit?) RayCast(Component root, Ray ray, out Vector3 point) { point = Vector3.zero; if (root.gameObject.scene.GetPhysicsScene() .Raycast(ray.origin, ray.direction, out var hit)) { point = hit.point; return (true, hit); } return (false, null); } /// /// only use when determined root /// /// /// /// /// private static (Vector3, RaycastHit?) RaycastPoint(Component root, Vector2 screenPoint, float distance = 20) { var ray = SceneView.currentDrawingSceneView.camera.ScreenPointToRay(screenPoint); var result = RayCast(root, ray, out var point); if (!result.Item1) { point = ray.origin + ray.direction.normalized * distance; } return (point, result.Item2); } /// /// for mesh with irregular shape the returned result is incorrect /// missing some direction /// /// /// /// /// private static Vector3 GetSpawnPosition(Renderer rendererAttach, Renderer rendererOther, RaycastHit hitInfo) { var boundsAttach = rendererAttach.bounds; var boundsOther = rendererOther.bounds; var otherPos = hitInfo.collider.gameObject.transform.position; var pointPos = hitInfo.point; int isSpawnRighSide; if (Mathf.Abs(otherPos.x - pointPos.x) >= boundsOther.size.x / 2) { isSpawnRighSide = otherPos.x > pointPos.x ? -1 : 1; } else { isSpawnRighSide = 0; } int isSpawnUpSide; if (Mathf.Abs(otherPos.y - pointPos.y) >= boundsOther.size.y / 2) { isSpawnUpSide = otherPos.y > pointPos.y ? -1 : 1; } else { isSpawnUpSide = 0; } int isSpawnForwardSide; if (Mathf.Abs(otherPos.z - pointPos.z) >= boundsOther.size.z / 2) { isSpawnForwardSide = otherPos.z > pointPos.z ? -1 : 1; } else { isSpawnForwardSide = 0; } return new Vector3(hitInfo.point.x + (boundsAttach.size.x / 2 * isSpawnRighSide), hitInfo.point.y + (boundsAttach.size.y / 2 * isSpawnUpSide), hitInfo.point.z + (boundsAttach.size.z / 2 * isSpawnForwardSide)); } /// /// Spawn pickup object /// /// /// private static void AddPickObject(PickObject pickObject, Vector3 worldPos) { if (pickObject?.pickedObject) { var inst = (GameObject)PrefabUtility.InstantiatePrefab(pickObject.pickedObject, GetParent()); inst.transform.position = worldPos; Undo.RegisterCreatedObjectUndo(inst.gameObject, "Create pick obj"); Selection.activeObject = inst; } } private static Transform GetParent() { Transform parent = null; var currentPrefabState = GetCurrentPrefabStage(); if (currentPrefabState != null) { var prefabRoot = currentPrefabState.prefabContentsRoot.transform; switch (LevelSystemEditorSetting.Instance .optionsSpawn[LevelSystemEditorSetting.Instance.SelectedSpawn].ToLower()) { case "default": parent = prefabRoot; break; case "index": if (LevelSystemEditorSetting.Instance.RootIndexSpawn < 0) parent = prefabRoot; else if (prefabRoot.childCount - 1 > LevelSystemEditorSetting.Instance.RootIndexSpawn) parent = prefabRoot.GetChild(LevelSystemEditorSetting.Instance.RootIndexSpawn); else parent = prefabRoot; break; case "custom": parent = LevelSystemEditorSetting.Instance.RootSpawn ? LevelSystemEditorSetting.Instance.RootSpawn.transform : prefabRoot; break; } } else { switch (LevelSystemEditorSetting.Instance .optionsSpawn[LevelSystemEditorSetting.Instance.SelectedSpawn].ToLower()) { case "default": case "index": parent = null; break; case "custom": parent = LevelSystemEditorSetting.Instance.RootSpawn ? LevelSystemEditorSetting.Instance.RootSpawn.transform : null; break; } } return parent; } private static PrefabStage GetCurrentPrefabStage() { return PrefabStageUtility.GetCurrentPrefabStage(); } /// /// Calculate count item pickup can display /// /// /// /// /// /// /// /// /// // ReSharper disable once UnusedMethodReturnValue.Local private static bool CalculateIdealCount(float availableSpace, float minSize, float maxSize, float spacing, int defaultCount, out int count, out float size) { float halfSpacing = spacing / 2f; int minCount = Mathf.FloorToInt(availableSpace / (maxSize + halfSpacing)); int maxCount = Mathf.FloorToInt(availableSpace / (minSize + halfSpacing)); bool goodness = defaultCount >= minCount && defaultCount <= maxCount; count = Mathf.Clamp(defaultCount, minCount, maxCount); size = (availableSpace - halfSpacing * (count - 1) - (count - 1) * (count / 10f)) / count; return goodness; } // private static void ClearEditor(EditorWindow window) // { // window.Repaint(); // } } } ================================================ FILE: VirtueSky/ControlPanel/CPLevelEditorDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: 804a530dac8b4b5fbee5eedbef28d5ac timeCreated: 1704943685 ================================================ FILE: VirtueSky/ControlPanel/CPLocalizationDrawer.cs ================================================ using System; using System.Collections; using System.Collections.Generic; using System.Linq; using UnityEditor; using UnityEditor.IMGUI.Controls; using UnityEngine; using VirtueSky.Localization; using VirtueSky.LocalizationEditor; using VirtueSky.UtilsEditor; namespace VirtueSky.ControlPanel.Editor { public class CPLocalizationDrawer { private static GoogleTranslator Translator => new(LocaleSettings.GoogleTranslateApiKey); private static LocaleTabType localeTabType = LocaleTabType.Setting; private static VirtueSky.Localization.LocaleSettings _settings; private static UnityEditor.Editor _editor; private static Vector2 scroll = Vector2.zero; private static LocaleTabType _currentLocaleTab = LocaleTabType.Setting; private static TreeViewState _treeViewState; public static LocaleTreeView _localeTreeView; private static SearchField _localeSearchField; private static float cacheYToolBarRect; private static float cacheWidth; private static bool _localeInitialized; private static MultiColumnHeaderState _multiColumnHeaderState; private struct EditorCommands { public const string DUPLICATE = "Duplicate"; public const string DELETE = "Delete"; public const string FRAME_SELECTED = "FrameSelected"; } public static void OnEnable() { Init(); } private static void Init() { if (_editor != null) _editor = null; _settings = CreateAsset.GetScriptableAsset(); _editor = UnityEditor.Editor.CreateEditor(_settings); } public static void OnDrawLocalization(Rect position) { GUILayout.Space(10); GUILayout.BeginVertical(); CPUtility.DrawHeaderIcon(StatePanelControl.Localization, "Localization"); GUILayout.Space(10); DrawTab(); GUILayout.Space(10); CPUtility.GuiLine(2); GUILayout.Space(10); switch (localeTabType) { case LocaleTabType.Setting: DrawSetting(position); break; case LocaleTabType.Explore: DrawExplore(position); break; } GUILayout.EndVertical(); } static void DrawTab() { EditorGUILayout.BeginHorizontal(); bool clickSetting = GUILayout.Toggle(localeTabType == LocaleTabType.Setting, "Setting", GUI.skin.button, GUILayout.ExpandWidth(true), GUILayout.Height(25)); if (clickSetting && localeTabType != LocaleTabType.Setting) { localeTabType = LocaleTabType.Setting; } bool clickPickup = GUILayout.Toggle(localeTabType == LocaleTabType.Explore, "Explore", GUI.skin.button, GUILayout.ExpandWidth(true), GUILayout.Height(25)); if (clickPickup && localeTabType != LocaleTabType.Explore) { localeTabType = LocaleTabType.Explore; } EditorGUILayout.EndHorizontal(); } private static void DrawSetting(Rect position) { scroll = EditorGUILayout.BeginScrollView(scroll); if (_settings == null) { if (GUILayout.Button("Create LocaleSettings")) { _settings = CreateAsset.CreateAndGetScriptableAsset("/Localization/Resources", isPingAsset: false); Init(); } } else { if (_editor == null) { EditorGUILayout.HelpBox("Couldn't create the settings editor.", MessageType.Error); return; } _editor.OnInspectorGUI(); GUILayout.Space(10); CPUtility.GuiLine(2); GUILayout.Space(10); CPUtility.DrawHeader("Install Sdk"); GUILayout.Space(10); CPUtility.DrawButtonInstallPackage("Install Baking Sheet", "Remove Baking Sheet", ConstantPackage.PackageNameBakingSheet, ConstantPackage.MaxVersionBakingSheet); GUILayout.Space(10); CPUtility.GuiLine(2); GUILayout.Space(10); CPUtility.DrawHeader("Define Symbols"); GUILayout.Space(10); CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_BAKINGSHEET); } GUILayout.Space(10); CPUtility.GuiLine(2); GUILayout.Space(10); CPUtility.DrawHeader("Ping LocaleSettings"); GUILayout.Space(10); if (GUILayout.Button("Ping")) { if (_settings == null) { Debug.LogError("LocaleSettings have not been created yet"); } else { EditorGUIUtility.PingObject(_settings); Selection.activeObject = _settings; } } GUILayout.Space(10); EditorGUILayout.EndScrollView(); GUILayout.Space(10); } private static void DrawExplore(Rect position) { cacheYToolBarRect = GUILayoutUtility.GetLastRect().y + 10; cacheWidth = position.width - ConstantControlPanel.POSITION_X_START_CONTENT - 10; Rect ToolbarRect = new(ConstantControlPanel.POSITION_X_START_CONTENT + 5, cacheYToolBarRect, cacheWidth, 5); Rect BottomToolbarRect = new(ConstantControlPanel.POSITION_X_START_CONTENT + 5, position.height - 20, cacheWidth, 20); InitializeIfNeeded(ref _treeViewState, ref _localeTreeView, ref _multiColumnHeaderState, cacheWidth, ref _localeSearchField, ref _localeInitialized); HandleEditorCommands(ref _localeTreeView); SearchBarView(ref _localeTreeView, ref _localeSearchField, ToolbarRect); BottomToolbarView(ref _localeTreeView, BottomToolbarRect); Rect BodyViewRect = new(ConstantControlPanel.POSITION_X_START_CONTENT + 5, cacheYToolBarRect + 20, cacheWidth, position.height - cacheYToolBarRect - 45); BodyView(ref _localeTreeView, BodyViewRect); } private static void InitializeIfNeeded( ref TreeViewState treeViewState, ref LocaleTreeView treeView, ref MultiColumnHeaderState multiColumnHeaderState, float bodyViewRectWidth, ref SearchField searchField, ref bool initialized) { if (treeViewState == null || treeView == null || searchField == null) initialized = false; if (!initialized) { if (treeViewState == null) treeViewState = new TreeViewState(); bool firstInit = multiColumnHeaderState == null; var headerState = LocaleTreeView.CreateDefaultMultiColumnHeaderState(bodyViewRectWidth); if (MultiColumnHeaderState.CanOverwriteSerializedFields(multiColumnHeaderState, headerState)) { MultiColumnHeaderState.OverwriteSerializedFields(multiColumnHeaderState, headerState); } multiColumnHeaderState = headerState; var multiColumnHeader = new MultiColumnHeader(headerState); if (firstInit) multiColumnHeader.ResizeToFit(); treeView = new LocaleTreeView(treeViewState, multiColumnHeader); searchField = new SearchField(); searchField.downOrUpArrowKeyPressed += treeView.SetFocusAndEnsureSelectedItem; initialized = true; } } private static void HandleEditorCommands(ref LocaleTreeView treeView) { var selectedItems = GetSelectedAssetItems(ref treeView).ToList(); if (selectedItems.Any()) { var e = Event.current; if (e.type == EventType.ValidateCommand && (e.commandName == EditorCommands.DELETE || e.commandName == EditorCommands.DUPLICATE || e.commandName == EditorCommands.FRAME_SELECTED)) { e.Use(); } if (e.type == EventType.ExecuteCommand) { switch (e.commandName) { case EditorCommands.DELETE: DeleteAssetItems(selectedItems, ref treeView); break; case EditorCommands.DUPLICATE: DuplicateAssetItems(selectedItems, ref treeView); break; case EditorCommands.FRAME_SELECTED: RevealLocalizedAsset(selectedItems.FirstOrDefault()); break; } } } } private static void DeleteAssetItems(IEnumerable items, ref LocaleTreeView treeView) { foreach (var item in items.ToList()) { string assetPath = AssetDatabase.GetAssetPath(item.Asset.GetInstanceID()); AssetDatabase.MoveAssetToTrash(assetPath); } // refresh view treeView.Reload(); } private static void DuplicateAssetItems(IEnumerable items, ref LocaleTreeView treeView) { foreach (var item in items) { string assetPath = AssetDatabase.GetAssetPath(item.Asset.GetInstanceID()); string newPath = AssetDatabase.GenerateUniqueAssetPath(assetPath); AssetDatabase.CopyAsset(assetPath, newPath); } // refresh view treeView.Reload(); } private static void RevealLocalizedAsset(AssetTreeViewItem assetTreeViewItem) { Debug.Assert(assetTreeViewItem != null); EditorGUIUtility.PingObject(assetTreeViewItem.Asset); } private static IEnumerable GetSelectedAssetItems(ref LocaleTreeView treeView) { return GetSelectedItemsAs(ref treeView); } private static IEnumerable GetSelectedItemsAs(ref LocaleTreeView treeView) where T : TreeViewItem { if (treeView == null) return Enumerable.Empty(); var selection = treeView.GetSelection(); var items = treeView.GetRows().Where(item => item as T != null && selection.Contains(item.id)); return items.Cast(); } private static void SearchBarView(ref LocaleTreeView treeView, ref SearchField searchField, Rect rect) { treeView.searchString = searchField.OnGUI(rect, treeView.searchString); } private static void BodyView(ref LocaleTreeView treeView, Rect rect) { treeView.OnGUI(rect); OnContextMenu(ref treeView, rect); } private static void OnContextMenu(ref LocaleTreeView treeView, Rect rect) { var currentEvent = Event.current; var mousePosition = currentEvent.mousePosition; if (rect.Contains(mousePosition) && currentEvent.type == EventType.ContextClick) { TryGetSelectedTreeViewItem(ref treeView, out var assetTreeViewItem, out var localeTreeViewItem); if (assetTreeViewItem != null && localeTreeViewItem != null) { OnLocaleItemContextMenu(assetTreeViewItem, localeTreeViewItem); currentEvent.Use(); } else { OnAssetItemContextMenu(ref assetTreeViewItem, ref mousePosition); currentEvent.Use(); } } } private static void TryGetSelectedTreeViewItem(ref LocaleTreeView treeView, out AssetTreeViewItem assetTreeViewItem, out LocaleTreeViewItem localeTreeViewItem) { var selectedItem = treeView.GetSelectedItem(); assetTreeViewItem = selectedItem as AssetTreeViewItem; localeTreeViewItem = selectedItem as LocaleTreeViewItem; if (assetTreeViewItem == null && selectedItem != null) { assetTreeViewItem = ((LocaleTreeViewItem)selectedItem).Parent; } } private static void OnAssetItemContextMenu(ref AssetTreeViewItem assetTreeViewItem, ref Vector2 mousePosition) { const string itemCreate = "Create"; const string itemRename = "Rename"; const string itemDelete = "Delete"; if (Event.current != null) { mousePosition = Event.current.mousePosition; } var menu = new GenericMenu(); menu.AddItem(new GUIContent(itemCreate), false, AssetItemContextMenu_Create, mousePosition); if (assetTreeViewItem == null) { menu.AddDisabledItem(new GUIContent(itemRename)); menu.AddDisabledItem(new GUIContent(itemDelete)); } else { menu.AddItem(new GUIContent(itemRename), false, AssetItemContextMenu_Rename); menu.AddItem(new GUIContent(itemDelete), false, AssetItemContextMenu_Delete); } menu.ShowAsContext(); } private static void AssetItemContextMenu_Create(object mousePosition) { CreateLocalizedAssetPopup((Vector2)mousePosition); } private static void CreateLocalizedAssetPopup(Vector2 mousePosition) { var popupPosition = new Rect(mousePosition, Vector2.zero); EditorUtility.DisplayPopupMenu(popupPosition, "Assets/Create/Sunflower/Localization/", null); } private static void AssetItemContextMenu_Rename() { TryGetSelectedTreeViewItem(ref _localeTreeView, out var assetTreeViewItem, out _); RenameLocalizedAsset(ref _localeTreeView, assetTreeViewItem); } private static void RenameLocalizedAsset(ref LocaleTreeView treeView, AssetTreeViewItem assetTreeViewItem) { Debug.Assert(assetTreeViewItem != null); treeView.BeginRename(assetTreeViewItem); } private static void AssetItemContextMenu_Delete() { DeleteAssetItems(GetSelectedAssetItems(ref _localeTreeView), ref _localeTreeView); } private static void OnLocaleItemContextMenu(AssetTreeViewItem assetTreeViewItem, LocaleTreeViewItem localeTreeViewItem) { Debug.Assert(assetTreeViewItem != null); Debug.Assert(localeTreeViewItem != null); var menu = new GenericMenu(); menu.AddItem(new GUIContent("Make default"), false, LocaleItemContextMenu_MakeDefault); menu.AddItem(new GUIContent("Remove"), false, LocaleItemContextMenu_Remove); menu.ShowAsContext(); } private static void LocaleItemContextMenu_MakeDefault() { TryGetSelectedTreeViewItem(ref _localeTreeView, out var assetTreeViewItem, out var localeTreeViewItem); MakeLocaleDefault(ref _localeTreeView, assetTreeViewItem, localeTreeViewItem); } private static void LocaleItemContextMenu_Remove() { TryGetSelectedTreeViewItem(ref _localeTreeView, out var assetTreeViewItem, out var localeTreeViewItem); RemoveLocale(ref _localeTreeView, assetTreeViewItem.Asset, localeTreeViewItem.LocaleItem); } private static void MakeLocaleDefault(ref LocaleTreeView treeView, AssetTreeViewItem assetTreeViewItem, LocaleTreeViewItem localeTreeViewItem) { var localizedAsset = assetTreeViewItem.Asset; var language = localeTreeViewItem.LocaleItem.Language; var serializedObject = new SerializedObject(localizedAsset); serializedObject.Update(); var elements = serializedObject.FindProperty("items"); if (elements != null && elements.arraySize > 1) { int index = Array.FindIndex(localizedAsset.LocaleItems, x => x.Language == language); if (index >= 0) { language = new Language(language.Name, language.Code, language.Custom); elements.MoveArrayElement(index, 0); serializedObject.ApplyModifiedProperties(); treeView.Reload(); Debug.Log(localizedAsset.name + ":" + language + " was set as the default language."); } } } private static void RemoveLocale(ref LocaleTreeView treeView, ScriptableLocaleBase scriptable, LocaleItemBase localeItem) { if (ScriptableLocaleEditor.RemoveLocale(scriptable, localeItem)) { treeView.Reload(); } } private static void BottomToolbarView(ref LocaleTreeView treeView, Rect rect) { var backgroundStyle = new GUIStyle(GUI.skin.box) { normal = { background = CreateTexture(new Color(0.55f, 0.55f, 0.55f, 1f)) } }; var toolbarStyle = new GUIStyle(EditorStyles.toolbar); var padding = toolbarStyle.padding; padding.left = 0; padding.right = 0; toolbarStyle.padding = padding; // Toolbar background. GUI.Box(new Rect(rect.x, rect.y, rect.width, rect.height - 1), GUIContent.none, backgroundStyle); // Toolbar itself. GUILayout.BeginArea(new Rect(rect.x, rect.y + 1, rect.width - 1, rect.height)); using (new EditorGUILayout.HorizontalScope(toolbarStyle)) { TreeViewControls(ref treeView); LocalizedAssetControls(ref treeView); GUILayout.FlexibleSpace(); LocaleItemControls(ref treeView); } GUILayout.EndArea(); } public static Texture2D CreateTexture(Color color) { var result = new Texture2D(1, 1, TextureFormat.RGBA32, false); result.SetPixel(0, 0, color); result.Apply(); return result; } private static void TreeViewControls(ref LocaleTreeView treeView) { if (GUILayout.Button(Uniform.IconContent("d_SettingsIcon@2x", "Open settings"), EditorStyles.toolbarButton, GUILayout.Width(25))) { var settings = LocaleSettings.Instance; if (settings) Selection.activeObject = settings; localeTabType = LocaleTabType.Setting; } if (GUILayout.Button(Uniform.IconContent("refresh", "Refresh the window"), EditorStyles.toolbarButton)) { treeView?.Reload(); } } private static void LocalizedAssetControls(ref LocaleTreeView treeView) { if (GUILayout.Button(new GUIContent("Create", "Create a new localized asset."), EditorStyles.toolbarDropDown)) { var mousePosition = Event.current.mousePosition; CreateLocalizedAssetPopup(mousePosition); } var selectedItem = treeView.GetSelectedItem() as AssetTreeViewItem; GUI.enabled = selectedItem != null; if (GUILayout.Button(new GUIContent("Rename", "Rename the selected localized asset."), EditorStyles.toolbarButton)) { RenameLocalizedAsset(ref treeView, selectedItem); } if (GUILayout.Button(new GUIContent("Delete", "Delete the selected localized asset."), EditorStyles.toolbarButton)) { DeleteAssetItems(new[] { selectedItem }, ref treeView); } GUI.enabled = true; if (GUILayout.Button(new GUIContent("Import", "Import text from csv file"), EditorStyles.toolbarButton)) { LocaleEditorUtil.Import(); } if (GUILayout.Button(new GUIContent("Export", "Export text to csv file"), EditorStyles.toolbarButton)) { LocaleEditorUtil.Export(); } } private static void LocaleItemControls(ref LocaleTreeView treeView) { TryGetSelectedTreeViewItem(ref treeView, out var assetTreeViewItem, out var localeTreeViewItem); GUI.enabled = assetTreeViewItem != null && assetTreeViewItem.Asset.GetGenericType == typeof(string); if (GUILayout.Button(new GUIContent("Translate By", "Translate missing locales."), EditorStyles.toolbarButton)) { TranslateMissingLocalesWithMenu(assetTreeViewItem?.Asset); } GUI.enabled = !Application.isPlaying; if (GUILayout.Button(new GUIContent("Translate All", "Translate all missing locales."), EditorStyles.toolbarButton)) { if (EditorUtility.DisplayDialog("Translate All", "Are you sure you wish to translate all missing locale?\nThis action cannot be reversed.", "Yes", "No")) { Debug.Log("[Localization] Starting translate all LocaleText!"); EditorCoroutine.Start(ExecuteTranslateProcess(treeView)); } } if (GUILayout.Button( new GUIContent("Fill All LocaleText", "Fill language same with AvaiableLanguage for all LocaleText."), EditorStyles.toolbarButton)) { if (EditorUtility.DisplayDialog("Fill language same AvaiableLanguage for all LocaleText", "Are you sure you wish to fill language same AvaiableLanguage for all LocaleText?\nThis action cannot be reversed.", "Yes", "No")) { EditorCoroutine.Start(ExecuteFillMissingLangProcess(treeView)); } } // First element is already default. GUI.enabled = Application.isPlaying; if (GUILayout.Button( new GUIContent("App Language", Application.isPlaying ? "Set application language" : "Application language can be set in play mode"), EditorStyles.toolbarButton)) { var currentLanguage = Locale.CurrentLanguage; var languages = LocaleSettings.AvailableLanguages; var menu = new GenericMenu(); foreach (var language in languages) { menu.AddItem(new GUIContent(language.Name), language == currentLanguage, AppLanguageContextMenu, language); } menu.ShowAsContext(); } GUI.enabled = assetTreeViewItem != null; if (GUILayout.Button(Uniform.IconContent("Toolbar Plus", "Add locale for selected asset."), EditorStyles.toolbarButton)) { AddLocale(ref treeView, assetTreeViewItem?.Asset); } GUI.enabled = localeTreeViewItem != null; if (GUILayout.Button(Uniform.IconContent("Toolbar Minus", "Remove selected locale."), EditorStyles.toolbarButton)) { RemoveLocale(ref treeView, assetTreeViewItem?.Asset, localeTreeViewItem?.LocaleItem); } GUI.enabled = true; IEnumerator ExecuteFillMissingLangProcess(LocaleTreeView treeView) { Debug.Log( "[Localization] Starting fill language same with AvaiableLanguage for LocaleText!" ); var rows = treeView.GetRows(); foreach (var viewItem in rows.ToList()) { var assetItem = viewItem as AssetTreeViewItem; FillLanguageSameAvaiableLanguage(assetItem?.Asset); yield return null; } treeView.Reload(); Debug.Log("[Localization] End fill language all LocaleText!"); } IEnumerator ExecuteTranslateProcess(LocaleTreeView treeView) { SessionState.EraseInt("translate_all_locale_text_count"); var rows = treeView.GetRows(); foreach (var viewItem in rows.ToList()) { var assetItem = viewItem as AssetTreeViewItem; TranslateMissingLocales(assetItem?.Asset); yield return new WaitForSeconds(0.15f); } Debug.Log("[Localization] End translate all LocaleText!"); Debug.Log( "Total LocaleText Translated is :" + SessionState.GetInt("translate_all_locale_text_count", 0)); SessionState.EraseInt("translate_all_locale_text_count"); } } private static void TranslateMissingLocalesWithMenu(ScriptableLocaleBase asset) { var localeText = asset as LocaleText; var options = new List(); if (localeText != null) { Debug.Log("[Localization] Starting Translate LocaleText: " + localeText.name); foreach (var locale in localeText.TypedLocaleItems) { if (!string.IsNullOrEmpty(locale.Value)) options.Add(new GUIContent(locale.Language.ToString())); } var mousePosition = Event.current.mousePosition; var popupPosition = new Rect(mousePosition.x, mousePosition.y, 0, 0); EditorUtility.DisplayCustomMenu(popupPosition, options.ToArray(), -1, TranslateSelected, localeText); } } /// /// Translate language by first language value /// /// private static void TranslateMissingLocales(ScriptableLocaleBase asset) { var localizedText = asset as LocaleText; var options = new List(); if (localizedText != null) { foreach (var locale in localizedText.TypedLocaleItems) { if (!string.IsNullOrEmpty(locale.Value)) options.Add(new GUIContent(locale.Language.ToString())); } TranslateSelected(localizedText, options.Select(c => c.text).ToArray(), 0); } } /// /// Translate language by first language value /// /// private static void FillLanguageSameAvaiableLanguage(ScriptableLocaleBase asset) { var localizedText = asset as LocaleText; if (localizedText != null) { foreach (var item in asset.LocaleItems.ToList()) { int index = Array.FindIndex(asset.LocaleItems, x => x.Language == item.Language); if (!LocaleSettings.AvailableLanguages.Contains(asset.LocaleItems[index].Language)) { asset.LocaleItems.ToList().RemoveAt(index); } } if (asset.LocaleItems.Length < LocaleSettings.AvailableLanguages.Count) { foreach (var lang in LocaleSettings.AvailableLanguages) { int index = Array.FindIndex(asset.LocaleItems, x => x.Language == lang); if (index >= 0) continue; ScriptableLocaleEditor.AddLocale(asset); index = asset.LocaleItems.Length - 1; var localeItem = asset.LocaleItems[index]; localeItem.Language = lang; localeItem.ObjectValue = ""; } } } } private static void TranslateSelected(object userData, string[] options, int selected) { var localizedText = (LocaleText)userData; var selectedLanguage = LocaleSettings.AllLanguages.FirstOrDefault(x => x.Name == options[selected]); if (selectedLanguage == null) { Debug.Assert(false, "Selected language not found in LocaleSettings.AllLanguages."); return; } if (!localizedText.TryGetLocaleValue(selectedLanguage, out string textValue)) { Debug.Assert(false, "Selected language not exist in " + localizedText.name); return; } foreach (var locale in localizedText.TypedLocaleItems) { if (string.IsNullOrEmpty(locale.Value)) { var localeItem = locale; Translator.Translate(new GoogleTranslateRequest(selectedLanguage, locale.Language, textValue), e => { var response = e.Responses.FirstOrDefault(); if (response != null) { localeItem.Value = response.translatedText; SessionState.SetInt("translate_all_locale_text_count", SessionState.GetInt("translate_all_locale_text_count", 0) + 1); Debug.Log("[Localization] Translate Successfull: " + localizedText.name); } EditorUtility.SetDirty(localizedText); }, e => { Debug.LogError("Response (" + e.ResponseCode + "): " + e.Message); }); } } } private static void AppLanguageContextMenu(object language) { Locale.CurrentLanguage = (Language)language; } private static void AddLocale(ref LocaleTreeView localeTreeView, ScriptableLocaleBase localizedAsset) { if (ScriptableLocaleEditor.AddLocale(localizedAsset)) localeTreeView.Reload(); } } public enum LocaleTabType { Setting, Explore } /// /// Refreshes localization tab wizard if is opened. /// public class ScriptableLocalePostprocessor : AssetPostprocessor { private static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths) { if (CPLocalizationDrawer._localeTreeView != null) CPLocalizationDrawer._localeTreeView?.Reload(); } } } ================================================ FILE: VirtueSky/ControlPanel/CPLocalizationDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: 6ff665b53f20434c95bcc686b1bdeffd timeCreated: 1729159142 ================================================ FILE: VirtueSky/ControlPanel/CPNotificationChanelDrawer.cs ================================================ using UnityEditor; using UnityEngine; using VirtueSky.UtilsEditor; namespace VirtueSky.ControlPanel.Editor { public static class CPNotificationChanelDrawer { public static void OnDrawNotificationChanel(Rect position) { GUILayout.Space(10); GUILayout.BeginVertical(); CPUtility.DrawHeaderIcon(StatePanelControl.NotificationsChanel, "Notifications"); GUILayout.Space(10); if (GUILayout.Button("Create Notification Chanel")) { NotificationWindowEditor.CreateNotificationChannel(); } GUILayout.Space(10); CPUtility.DrawLineLastRectY(3, ConstantControlPanel.POSITION_X_START_CONTENT, position.width); GUILayout.Space(10); CPUtility.DrawHeader("Install Sdk"); GUILayout.Space(10); CPUtility.DrawButtonInstallPackage("Install Mobile Notifications", "Remove Mobile Notifications", ConstantPackage.PackageNameMobileNotification, ConstantPackage.MaxVersionMobileNotification); GUILayout.Space(10); CPUtility.DrawLineLastRectY(3, ConstantControlPanel.POSITION_X_START_CONTENT, position.width); GUILayout.Space(10); CPUtility.DrawHeader("Define Symbols"); GUILayout.Space(10); #if !VIRTUESKY_NOTIFICATION EditorGUILayout.HelpBox( $"Add scripting define symbols \"{ConstantDefineSymbols.VIRTUESKY_NOTIFICATION}\" to use IAP", MessageType.Info); #endif CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_NOTIFICATION); GUILayout.EndVertical(); } } } ================================================ FILE: VirtueSky/ControlPanel/CPNotificationChanelDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: 3f51fe616e2e426d8bafbc2de7a103d9 timeCreated: 1704943768 ================================================ FILE: VirtueSky/ControlPanel/CPRegisterPackageDrawer.cs ================================================ using UnityEditor; using UnityEngine; using VirtueSky.UtilsEditor; namespace VirtueSky.ControlPanel.Editor { public static class CPRegisterPackageDrawer { private static Vector2 scrollPositionFileManifest = Vector2.zero; private static Vector2 scrollPositionAddSomePackage = Vector2.zero; public static void OnDrawRegisterPackageByManifest(Rect position) { GUILayout.Space(10); GUILayout.BeginVertical(); CPUtility.DrawHeaderIcon(StatePanelControl.RegisterPackage, "Register Package"); GUILayout.Space(10); scrollPositionAddSomePackage = EditorGUILayout.BeginScrollView(scrollPositionAddSomePackage, GUILayout.Height(150)); DrawButtonAddSomePackage(); EditorGUILayout.EndScrollView(); GUILayout.Space(10); CPUtility.DrawLineLastRectY(3, ConstantControlPanel.POSITION_X_START_CONTENT, position.width); GUILayout.Space(10); GUILayout.Label("Manifest.json", EditorStyles.boldLabel); GUILayout.Space(10); if (GUILayout.Button("Resolve Package")) { RegistryManager.Resolve(); } scrollPositionFileManifest = EditorGUILayout.BeginScrollView(scrollPositionFileManifest, GUILayout.Height(250)); string manifestContent = EditorGUILayout.TextArea( System.IO.File.ReadAllText(FileExtension.ManifestPath), GUILayout.ExpandHeight(true)); RegistryManager.WriteAllManifestContent(manifestContent); EditorGUILayout.EndScrollView(); GUILayout.EndVertical(); } static void DrawButtonAddSomePackage() { CPUtility.DrawButtonInstallPackage("Install Firebase App", "Remove Firebase App", ConstantPackage.PackageNameFirebaseApp, ConstantPackage.MaxVersionFirebaseApp); CPUtility.DrawButtonInstallPackage("Install Firebase Remote Config", "Remove Firebase Remote Config", ConstantPackage.PackageNameFirebaseRemoteConfig, ConstantPackage.MaxVersionFirebaseRemoteConfig); CPUtility.DrawButtonInstallPackage("Install Firebase Analytics", "Remove Firebase Analytics", ConstantPackage.PackageNameFirebaseAnalytics, ConstantPackage.MaxVersionFirebaseAnalytics); CPUtility.DrawButtonInstallPackage("Install Firebase Crashlytics", "Remove Firebase Crashlytics", ConstantPackage.PackageNameFirebaseCrashlytics, ConstantPackage.MaxVersionFirebaseCrashlytics); CPUtility.DrawButtonInstallPackage("Install Firebase Database", "Remove Firebase Database", ConstantPackage.PackageNameFirebaseDatabase, ConstantPackage.MaxVersionFirebaseDatabase); CPUtility.DrawButtonInstallPackage("Install Firebase Auth", "Remove Firebase Auth", ConstantPackage.PackageNameFirebaseAuth, ConstantPackage.MaxVersionFirebaseAuth); CPUtility.DrawButtonInstallPackage("Install Google External Dependency Manager", "Remove Google External Dependency Manager", ConstantPackage.PackageNameGGExternalDependencyManager, ConstantPackage.MaxVersionGGExternalDependencyManager); CPUtility.DrawButtonInstallPackage("Install Adjust", "Remove Adjust", ConstantPackage.PackageNameAdjust, ConstantPackage.MaxVersionAdjust); CPUtility.DrawButtonInstallPackage("Install In App Purchasing", "Remove In App Purchasing", ConstantPackage.PackageNameInAppPurchase, ConstantPackage.MaxVersionInAppPurchase); CPUtility.DrawButtonInstallPackage("Install AppsFlyer", "Remove AppsFlyer", ConstantPackage.PackageNameAppFlyer, ConstantPackage.MaxVersionAppFlyer); CPUtility.DrawButtonInstallPackage("Install Google Play Review", "Remove Google Play Review", ConstantPackage.PackageNameGGPlayReview, ConstantPackage.MaxVersionGGPlayReview); CPUtility.DrawButtonInstallPackage("Install Google Play Core", "Remove Google Play Core", ConstantPackage.PackageNameGGPlayCore, ConstantPackage.MaxVersionGGPlayCore); CPUtility.DrawButtonInstallPackage("Install Google Play Common", "Remove Google Play Common", ConstantPackage.PackageNameGGPlayCommon, ConstantPackage.MaxVersionGGPlayCommon); CPUtility.DrawButtonInstallPackage("Install Newtonsoft.Json", "Remove Newtonsoft.Json", ConstantPackage.PackageNameNewtonsoftJson, ConstantPackage.MaxVersionNewtonsoftJson); CPUtility.DrawButtonInstallPackage("Install PlayFab", "Remove PlayFab", ConstantPackage.PackageNamePlayFab, ConstantPackage.MaxVersionPlayFab); CPUtility.DrawButtonInstallPackage("Install Coffee UI Effect", "Remove Coffee UI Effect", ConstantPackage.PackageNameCoffeeUIEffect, ConstantPackage.MaxVersionCoffeeUIEffect); CPUtility.DrawButtonInstallPackage("Install Coffee UI Particle", "Remove Coffee UI Particle", ConstantPackage.PackageNameCoffeeUIParticle, ConstantPackage.MaxVersionCoffeeUIParticle); CPUtility.DrawButtonInstallPackage("Install iOS 14 Advertising Support", "Remove iOS 14 Advertising Support", ConstantPackage.PackageNameIOS14AdvertisingSupport, ConstantPackage.MaxVersionIOS14AdvertisingSupport); CPUtility.DrawButtonInstallPackage("Install Spine Csharp", "Remove Spine Csharp", ConstantPackage.PackageNameSpineCsharp, ConstantPackage.MaxVersionSpineCsharp); CPUtility.DrawButtonInstallPackage("Install Spine Unity", "Remove Spine Unity", ConstantPackage.PackageNameSpineUnity, ConstantPackage.MaxVersionSpineUnity); CPUtility.DrawButtonInstallPackage("Install UniTask", "Remove UniTask", ConstantPackage.PackageNameUniTask, ConstantPackage.MaxVersionUniTask); CPUtility.DrawButtonInstallPackage("Install Apple Sign In", "Remove Apple Sign In", ConstantPackage.PackageNameAppleSignIn, ConstantPackage.MaxVersionAppleSignIn); // CPUtility.DrawButtonInstallPackage("Install Animancer", "Remove Animancer", // ConstantPackage.PackageNameAnimancer, ConstantPackage.MaxVersionAnimancer); CPUtility.DrawButtonInstallPackage("Install Mobile Notifications", "Remove Mobile Notifications", ConstantPackage.PackageNameMobileNotification, ConstantPackage.MaxVersionMobileNotification); CPUtility.DrawButtonInstallPackage("Install Addressables", "Remove Addressables", ConstantPackage.PackageNameAddressables, ConstantPackage.MaxVersionAddressables); CPUtility.DrawButtonInstallPackage("Install Baking Sheet", "Remove Baking Sheet", ConstantPackage.PackageNameBakingSheet, ConstantPackage.MaxVersionBakingSheet); CPUtility.DrawButtonInstallPackage("Install Admob Sdk Plugin", "Remove Admob Sdk Plugin", ConstantPackage.PackageNameAdmob, ConstantPackage.VersionAdmob); CPUtility.DrawButtonInstallPackage("Install LevelPlay Sdk Plugin", "Remove LevelPlay Sdk Plugin", ConstantPackage.PackageNameLevelPlay, ConstantPackage.MaxVersionLevelPlay); if (GUILayout.Button("Install Google Play Game Service", GUILayout.Width(400))) { AssetDatabase.ImportPackage( FileExtension.GetPathFileInCurrentEnvironment( "VirtueSky/Utils/Editor/UnityPackage/google-play-game.unitypackage"), false); } } } } ================================================ FILE: VirtueSky/ControlPanel/CPRegisterPackageDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: 9fe0737fa3b94df294bf7173df5ca10f timeCreated: 1704943938 ================================================ FILE: VirtueSky/ControlPanel/CPScriptingDefineSymbolsDrawer.cs ================================================ using UnityEditor; using UnityEngine; using VirtueSky.UtilsEditor; namespace VirtueSky.ControlPanel.Editor { public static class CPScriptingDefineSymbolsDrawer { private static Vector2 scroll = Vector2.zero; public static void OnDrawScriptingDefineSymbols() { GUILayout.Space(10); GUILayout.BeginVertical(); CPUtility.DrawHeaderIcon(StatePanelControl.ScriptDefineSymbols, "Scripting Define Symbols"); GUILayout.Space(10); scroll = EditorGUILayout.BeginScrollView(scroll); CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_ADS); CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_APPLOVIN); CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_ADMOB); CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_LEVELPLAY); CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_ADJUST); CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_FIREBASE); CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_FIREBASE_ANALYTIC); CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_FIREBASE_REMOTECONFIG); CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_IAP); CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_RATING); CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_NOTIFICATION); CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_APPSFLYER); CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.PRIME_TWEEN_DOTWEEN_ADAPTER); CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.PRIME_TWEEN_SAFETY_CHECKS); CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_APPLE_AUTH); CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_GPGS); CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_SKELETON); CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_ANIMANCER); CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.UNITASK_ADDRESSABLE_SUPPORT); CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.UNITASK_DOTWEEN_SUPPORT); CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.UNITASK_TEXTMESHPRO_SUPPORT); CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_BAKINGSHEET); CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_UNITY_SERVICES); EditorGUILayout.EndScrollView(); GUILayout.Space(10); GUILayout.EndVertical(); } } } ================================================ FILE: VirtueSky/ControlPanel/CPScriptingDefineSymbolsDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: 2086ff90ddc5c6046b461194429b69d2 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/ControlPanel/CPSoEventDrawer.cs ================================================ using UnityEditor; using UnityEngine; using VirtueSky.Events; using VirtueSky.UtilsEditor; namespace VirtueSky.ControlPanel.Editor { public static class CPSoEventDrawer { static Vector2 scroll = Vector2.zero; private static bool isShowFielEvent = true; private static bool isShowFielEventResult; public static void OnDrawSoEvent() { GUILayout.Space(10); GUILayout.BeginVertical(); CPUtility.DrawHeaderIcon(StatePanelControl.SO_Event, "Scriptable Events"); GUILayout.Space(10); scroll = GUILayout.BeginScrollView(scroll); CPUtility.DrawToggle(ref isShowFielEvent, "Scriptable Event", DrawButtonEvent); GUILayout.Space(10); CPUtility.DrawToggle(ref isShowFielEventResult, "Scriptable Event-Result", DrawButtonEventResult); GUILayout.EndScrollView(); GUILayout.EndVertical(); } static void DrawButtonEvent() { if (GUILayout.Button("Create Boolean Event")) { EventWindowEditor.CreateEventBoolean(); } if (GUILayout.Button("Create Dictionary Event")) { EventWindowEditor.CreateEventDictionary(); } if (GUILayout.Button("Create No Param Event")) { EventWindowEditor.CreateEventNoParam(); } if (GUILayout.Button("Create Float Event")) { EventWindowEditor.CreateEventFloat(); } if (GUILayout.Button("Create Int Event")) { EventWindowEditor.CreateEventInt(); } if (GUILayout.Button("Create Object Event")) { EventWindowEditor.CreateEventObject(); } if (GUILayout.Button("Create Short Double Event")) { EventWindowEditor.CreateEventShortDouble(); } if (GUILayout.Button("Create String Event")) { EventWindowEditor.CreateEventString(); } if (GUILayout.Button("Create Vector3 Event")) { EventWindowEditor.CreateEventVector3(); } if (GUILayout.Button("Create Vector2 Event")) { EventWindowEditor.CreateEventVector2(); } if (GUILayout.Button("Create GameObject Event")) { EventWindowEditor.CreateEventGameObject(); } if (GUILayout.Button("Create Transform Event")) { EventWindowEditor.CreateEventTransform(); } } static void DrawButtonEventResult() { GUILayout.Space(10); Uniform.DrawGroupFoldout("cp_draw_bool_event_result", "Bool Event-Result", () => { if (GUILayout.Button("Bool Event - Bool Result")) { EventWindowEditor.CreateBoolEventBoolResult(); } if (GUILayout.Button("Bool Event - Float Result")) { EventWindowEditor.CreateBoolEventFloatResult(); } if (GUILayout.Button("Bool Event - Int Result")) { EventWindowEditor.CreateBoolEventIntResult(); } if (GUILayout.Button("Bool Event - Object Result")) { EventWindowEditor.CreateBoolEventObjectResult(); } if (GUILayout.Button("Bool Event - String Result")) { EventWindowEditor.CreateBoolEventStringResult(); } if (GUILayout.Button("Bool Event - Vector3 Result")) { EventWindowEditor.CreateBoolEventVector3Result(); } if (GUILayout.Button("Bool Event - GameObject Result")) { EventWindowEditor.CreateBoolEventGameObjectResult(); } if (GUILayout.Button("Bool Event - Transform Result")) { EventWindowEditor.CreateBoolEventTransformResult(); } }, false); GUILayout.Space(10); Uniform.DrawGroupFoldout("cp_draw_float_event_result", "Float Event-Result", () => { if (GUILayout.Button("Float Event - Bool Result")) { EventWindowEditor.CreateFloatEventBoolResult(); } if (GUILayout.Button("Float Event - Float Result")) { EventWindowEditor.CreateFloatEventFloatResult(); } if (GUILayout.Button("Float Event - Int Result")) { EventWindowEditor.CreateFloatEventIntResult(); } if (GUILayout.Button("Float Event - Object Result")) { EventWindowEditor.CreateFloatEventObjectResult(); } if (GUILayout.Button("Float Event - String Result")) { EventWindowEditor.CreateFloatEventStringResult(); } if (GUILayout.Button("Float Event - Vector3 Result")) { EventWindowEditor.CreateFloatEventVector3Result(); } if (GUILayout.Button("Float Event - GameObject Result")) { EventWindowEditor.CreateFloatEventGameObjectResult(); } if (GUILayout.Button("Float Event - Transform Result")) { EventWindowEditor.CreateFloatEventTransformResult(); } }, false); GUILayout.Space(10); Uniform.DrawGroupFoldout("cp_draw_int_event_result", "Int Event-Result", () => { if (GUILayout.Button("Int Event - Bool Result")) { EventWindowEditor.CreateIntEventBoolResult(); } if (GUILayout.Button("Int Event - Float Result")) { EventWindowEditor.CreateIntEventFloatResult(); } if (GUILayout.Button("Int Event - Int Result")) { EventWindowEditor.CreateIntEventIntResult(); } if (GUILayout.Button("Int Event - Object Result")) { EventWindowEditor.CreateIntEventObjectResult(); } if (GUILayout.Button("Int Event - String Result")) { EventWindowEditor.CreateIntEventStringResult(); } if (GUILayout.Button("Int Event - Vector3 Result")) { EventWindowEditor.CreateIntEventVector3Result(); } if (GUILayout.Button("Int Event - GameObject Result")) { EventWindowEditor.CreateIntEventGameObjectResult(); } if (GUILayout.Button("Int Event - Transform Result")) { EventWindowEditor.CreateIntEventTransformResult(); } }, false); GUILayout.Space(10); Uniform.DrawGroupFoldout("cp_draw_object_event_result", "Object Event-Result", () => { if (GUILayout.Button("Object Event - Bool Result")) { EventWindowEditor.CreateObjectEventBoolResult(); } if (GUILayout.Button("Object Event - Float Result")) { EventWindowEditor.CreateObjectEventFloatResult(); } if (GUILayout.Button("Object Event - Int Result")) { EventWindowEditor.CreateObjectEventIntResult(); } if (GUILayout.Button("Object Event - Object Result")) { EventWindowEditor.CreateObjectEventObjectResult(); } if (GUILayout.Button("Object Event - String Result")) { EventWindowEditor.CreateObjectEventStringResult(); } if (GUILayout.Button("Object Event - Vector3 Result")) { EventWindowEditor.CreateObjectEventVector3Result(); } if (GUILayout.Button("Object Event - GameObject Result")) { EventWindowEditor.CreateObjectEventGameObjectResult(); } if (GUILayout.Button("Object Event - Transform Result")) { EventWindowEditor.CreateObjectEventTransformResult(); } }, false); GUILayout.Space(10); Uniform.DrawGroupFoldout("cp_draw_string_event_result", "String Event-Result", () => { if (GUILayout.Button("String Event - Bool Result")) { EventWindowEditor.CreateStringEventBoolResult(); } if (GUILayout.Button("String Event - Float Result")) { EventWindowEditor.CreateStringEventFloatResult(); } if (GUILayout.Button("String Event - Int Result")) { EventWindowEditor.CreateStringEventIntResult(); } if (GUILayout.Button("String Event - Object Result")) { EventWindowEditor.CreateStringEventObjectResult(); } if (GUILayout.Button("String Event - String Result")) { EventWindowEditor.CreateStringEventStringResult(); } if (GUILayout.Button("String Event - Vector3 Result")) { EventWindowEditor.CreateStringEventVector3Result(); } if (GUILayout.Button("String Event - GameObject Result")) { EventWindowEditor.CreateStringEventGameObjectResult(); } if (GUILayout.Button("String Event - Transform Result")) { EventWindowEditor.CreateStringEventTransformResult(); } }, false); GUILayout.Space(10); Uniform.DrawGroupFoldout("cp_draw_vector3_event_result", "Vector3 Event-Result", () => { if (GUILayout.Button("Vector3 Event - Bool Result")) { EventWindowEditor.CreateVector3EventBoolResult(); } if (GUILayout.Button("Vector3 Event - Float Result")) { EventWindowEditor.CreateVector3EventFloatResult(); } if (GUILayout.Button("Vector3 Event - Int Result")) { EventWindowEditor.CreateVector3EventIntResult(); } if (GUILayout.Button("Vector3 Event - Object Result")) { EventWindowEditor.CreateVector3EventObjectResult(); } if (GUILayout.Button("Vector3 Event - String Result")) { EventWindowEditor.CreateVector3EventStringResult(); } if (GUILayout.Button("Vector3 Event - Vector3 Result")) { EventWindowEditor.CreateVector3EventVector3Result(); } if (GUILayout.Button("Vector3 Event - GameObject Result")) { EventWindowEditor.CreateVector3EventGameObjectResult(); } if (GUILayout.Button("Vector3 Event - Transform Result")) { EventWindowEditor.CreateVector3EventTransformResult(); } }, false); GUILayout.Space(10); Uniform.DrawGroupFoldout("cp_draw_event_no_param_result", "Event No Param-Result", () => { if (GUILayout.Button("Event No Param - Bool Result")) { EventWindowEditor.CreateEventNoParamBoolResult(); } if (GUILayout.Button("Event No Param - Float Result")) { EventWindowEditor.CreateEventNoParamFloatResult(); } if (GUILayout.Button("Event No Param - Int Result")) { EventWindowEditor.CreateEventNoParamIntResult(); } if (GUILayout.Button("Event No Param - Object Result")) { EventWindowEditor.CreateEventNoParamObjectResult(); } if (GUILayout.Button("Event No Param - String Result")) { EventWindowEditor.CreateEventNoParamStringResult(); } if (GUILayout.Button("Event No Param - Vector3 Result")) { EventWindowEditor.CreateEventNoParamVector3Result(); } if (GUILayout.Button("Event No Param - GameObject Result")) { EventWindowEditor.CreateEventNoParamGameObjectResult(); } if (GUILayout.Button("Event No Param - Transform Result")) { EventWindowEditor.CreateEventNoParamTransformResult(); } }, false); GUILayout.Space(10); Uniform.DrawGroupFoldout("cp_draw_gameobject_event_result", "GameObject Event-Result", () => { if (GUILayout.Button("GameObject Event - Bool Result")) { EventWindowEditor.CreateGameObjectEventBoolResult(); } if (GUILayout.Button("GameObject Event - Float Result")) { EventWindowEditor.CreateGameObjectEventFloatResult(); } if (GUILayout.Button("GameObject Event - GameObject Result")) { EventWindowEditor.CreateGameObjectEventGameObjectResult(); } if (GUILayout.Button("GameObject Event - Int Result")) { EventWindowEditor.CreateGameObjectEventIntResult(); } if (GUILayout.Button("GameObject Event - Object Result")) { EventWindowEditor.CreateGameObjectEventObjectResult(); } if (GUILayout.Button("GameObject Event - String Result")) { EventWindowEditor.CreateGameObjectEventStringResult(); } if (GUILayout.Button("GameObject Event - Transform Result")) { EventWindowEditor.CreateGameObjectEventTransformResult(); } if (GUILayout.Button("GameObject Event - Vector3 Result")) { EventWindowEditor.CreateGameObjectEventVector3Result(); } }, false); GUILayout.Space(10); Uniform.DrawGroupFoldout("cp_draw_transform_event_result", "Transform Event-Result", () => { if (GUILayout.Button("Transform Event - Bool Result")) { EventWindowEditor.CreateTransformEventBoolResult(); } if (GUILayout.Button("Transform Event - Float Result")) { EventWindowEditor.CreateTransformEventFloatResult(); } if (GUILayout.Button("Transform Event - GameObject Result")) { EventWindowEditor.CreateTransformEventGameObjectResult(); } if (GUILayout.Button("Transform Event - Int Result")) { EventWindowEditor.CreateTransformEventIntResult(); } if (GUILayout.Button("Transform Event - Object Result")) { EventWindowEditor.CreateTransformEventObjectResult(); } if (GUILayout.Button("Transform Event - String Result")) { EventWindowEditor.CreateTransformEventStringResult(); } if (GUILayout.Button("Transform Event - Transform Result")) { EventWindowEditor.CreateTransformEventTransformResult(); } if (GUILayout.Button("Transform Event - Vector3 Result")) { EventWindowEditor.CreateTransformEventVector3Result(); } }, false); } } } ================================================ FILE: VirtueSky/ControlPanel/CPSoEventDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: 583e9816b2c1ac148981eb62fc2ee4bb MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/ControlPanel/CPSoVariableDrawer.cs ================================================ using UnityEditor; using UnityEngine; using VirtueSky.Variables; namespace VirtueSky.ControlPanel.Editor { public static class CPSoVariableDrawer { public static void OnDrawSoVariable() { GUILayout.Space(10); GUILayout.BeginVertical(); CPUtility.DrawHeaderIcon(StatePanelControl.SO_Variable, "Scriptable Variables"); GUILayout.Space(10); if (GUILayout.Button("Create Boolean Variable")) { VariableWindowEditor.CreateVariableBoolean(); } if (GUILayout.Button("Create Float Variable")) { VariableWindowEditor.CreateVariableFloat(); } if (GUILayout.Button("Create Int Variable")) { VariableWindowEditor.CreateVariableInt(); } if (GUILayout.Button("Create Object Variable")) { VariableWindowEditor.CreateVariableObject(); } if (GUILayout.Button("Create Rect Variable")) { VariableWindowEditor.CreateVariableRect(); } if (GUILayout.Button("Create Short Double Variable")) { VariableWindowEditor.CreateVariableShortDouble(); } if (GUILayout.Button("Create String Variable")) { VariableWindowEditor.CreateVariableString(); } if (GUILayout.Button("Create Transform Variable")) { VariableWindowEditor.CreateVariableTransform(); } if (GUILayout.Button("Create Vector3 Variable")) { VariableWindowEditor.CreateVariableVector3(); } if (GUILayout.Button("Create Vector2 Variable")) { VariableWindowEditor.CreateVariableVector2(); } GUILayout.EndVertical(); } } } ================================================ FILE: VirtueSky/ControlPanel/CPSoVariableDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: d1e65b6d553c4a99bcad709550b26740 timeCreated: 1704943870 ================================================ FILE: VirtueSky/ControlPanel/CPUtility.cs ================================================ using UnityEditor; using UnityEngine; using VirtueSky.Inspector; using VirtueSky.Utils; using VirtueSky.UtilsEditor; namespace VirtueSky.ControlPanel.Editor { public class CPUtility { public static void DrawButtonInstallPackage(string labelInstall, string labelRemove, string packageName, string packageVersion, float withButton = 400) { EditorGUILayout.BeginHorizontal(); bool isInstall = RegistryManager.IsInstalledPackage(packageName); if (isInstall) { GUI.backgroundColor = CustomColor.Red.ToColor(); if (GUILayout.Button(labelRemove, GUILayout.Width(withButton))) { RegistryManager.Remove(packageName); RegistryManager.Resolve(); } } else { GUI.backgroundColor = CustomColor.Green.ToColor(); if (GUILayout.Button(labelInstall, GUILayout.Width(withButton))) { RegistryManager.AddOverrideVersion(packageName, packageVersion); } } GUI.backgroundColor = Color.white; GUILayout.Space(10); GUILayout.Toggle(isInstall, TextIsInstallPackage(isInstall)); EditorGUILayout.EndHorizontal(); } public static void DrawButtonAddDefineSymbols(string flagSymbols, float withButton = 400) { GUILayout.BeginHorizontal(); bool isAddSymbols = EditorScriptDefineSymbols.IsFlagEnabled(flagSymbols); string labelButton = isAddSymbols ? "Remove ---> " : "Add ---> "; if (isAddSymbols) { GUI.backgroundColor = CustomColor.Red.ToColor(); } else { GUI.backgroundColor = CustomColor.Green.ToColor(); } if (GUILayout.Button(labelButton + flagSymbols, GUILayout.Width(withButton))) { EditorScriptDefineSymbols.SwitchFlag(flagSymbols); } GUI.backgroundColor = Color.white; GUILayout.Space(10); GUILayout.Toggle(isAddSymbols, TextIsEnable(isAddSymbols)); GUILayout.EndHorizontal(); } public static string TextIsInstallPackage(bool isInstall) { return isInstall ? "Installed" : "Not installed"; } public static string TextIsEnable(bool condition) { return condition ? "Enable" : "Disable"; } public static void GuiLine(int i_height = 1, CustomColor customColor = CustomColor.Black) { Rect rect = EditorGUILayout.GetControlRect(false, i_height); rect.height = i_height; EditorGUI.DrawRect(rect, customColor.ToColor()); } public static void DrawCustomLine(float with, Vector2 positionPointStart, Vector2 positionPointEnd) { Handles.DrawAAPolyLine(with, positionPointStart, positionPointEnd); } public static void DrawLineLastRectY(float with, float posXPointStart, float posXPointEnd, float offsetY = 10) { Handles.DrawAAPolyLine(with, new Vector3(posXPointStart, GUILayoutUtility.GetLastRect().y + offsetY), new Vector3(posXPointEnd, GUILayoutUtility.GetLastRect().y + offsetY)); } public static void DrawLineLastRectX(float with, float posYPointStart, float posYPointEnd, float offsetX = 10) { Handles.DrawAAPolyLine(with, new Vector3(GUILayoutUtility.GetLastRect().x + offsetX, posYPointStart), new Vector3(GUILayoutUtility.GetLastRect().x + offsetX, posYPointEnd)); } public static void DrawToggle(ref bool value, string text, System.Action draw) { value = GUILayout.Toggle(value, text); if (value) { draw?.Invoke(); } } public static Texture2D GetIcon(StatePanelControl statePanelControl) { return statePanelControl switch { StatePanelControl.Advertising => EditorResources.IconAds, StatePanelControl.InAppPurchase => EditorResources.IconIap, StatePanelControl.Audio => EditorResources.IconAudio, StatePanelControl.InAppReview => EditorResources.IconInAppReview, StatePanelControl.NotificationsChanel => EditorResources.IconPushNotification, StatePanelControl.SO_Event => EditorResources.IconScriptableEvent, StatePanelControl.SO_Variable => EditorResources.IconScriptableVariable, StatePanelControl.Adjust => EditorResources.IconAdjust, StatePanelControl.AppsFlyer => EditorResources.IconAppsFlyer, StatePanelControl.GameService => EditorResources.IconGameService, StatePanelControl.Firebase => EditorResources.IconFirebase, StatePanelControl.Hierarchy => EditorResources.IconHierarchy, StatePanelControl.Extensions => EditorResources.IconExtension, StatePanelControl.FolderIcon => EditorResources.IconFolder, StatePanelControl.RegisterPackage => EditorResources.IconPackage, StatePanelControl.Localization => EditorResources.IconLocale, StatePanelControl.About => EditorResources.IconAbout, _ => EditorResources.IconUnity }; } public static void DrawHeaderIcon(StatePanelControl statePanelControl, string textHeader, int _fontSize = 17) { GUILayout.BeginHorizontal(); GUILayout.Box(CPUtility.GetIcon(statePanelControl), GUIStyle.none, GUILayout.Width(32), GUILayout.Height(32)); GUILayout.Space(3); GUIStyle headerStyle = new GUIStyle(EditorStyles.boldLabel) { fontSize = _fontSize }; GUILayout.Label(textHeader, headerStyle, GUILayout.ExpandHeight(false), GUILayout.Height(31)); GUILayout.EndHorizontal(); } public static void DrawHeader(string textHeader, int _fontSize = 16) { GUIStyle headerStyle = new GUIStyle(EditorStyles.boldLabel) { fontSize = _fontSize }; GUILayout.Label(textHeader, headerStyle); } } } ================================================ FILE: VirtueSky/ControlPanel/CPUtility.cs.meta ================================================ fileFormatVersion: 2 guid: b44fe5aa088e46d493f112ce6e0c9a40 timeCreated: 1706715670 ================================================ FILE: VirtueSky/ControlPanel/ConstantControlPanel.cs ================================================ namespace VirtueSky.ControlPanel.Editor { public class ConstantControlPanel { public static int WIDTH_CONTENT_BUTTON_STATE_CONTROL_PANEL = 210; public static int POSITION_X_START_CONTENT = WIDTH_CONTENT_BUTTON_STATE_CONTROL_PANEL + 5; } } ================================================ FILE: VirtueSky/ControlPanel/ConstantControlPanel.cs.meta ================================================ fileFormatVersion: 2 guid: 88226ff529e4471d831fd11c0cf8be54 timeCreated: 1707216394 ================================================ FILE: VirtueSky/ControlPanel/ConstantPackage.cs ================================================ namespace VirtueSky.ControlPanel.Editor { public class ConstantPackage { public const string VersionSunflower = "3.5.5-preview"; public const string PackageNameInAppPurchase = "com.unity.purchasing"; public const string MaxVersionInAppPurchase = "5.0.2"; public const string PackageNameNewtonsoftJson = "com.unity.nuget.newtonsoft-json"; public const string MaxVersionNewtonsoftJson = "3.2.1"; public const string PackageNameIOS14AdvertisingSupport = "com.unity.ads.ios-support"; public const string MaxVersionIOS14AdvertisingSupport = "1.2.0"; public const string PackageNameMobileNotification = "com.unity.mobile.notifications"; public const string MaxVersionMobileNotification = "2.4.2"; public const string PackageNameAddressables = "com.unity.addressables"; public const string MaxVersionAddressables = "2.7.4"; public const string PackageNameLevelPlay = "com.unity.services.levelplay"; public const string MaxVersionLevelPlay = "9.4.0"; public const string PackageNameAdmob = "com.google.ads.mobile"; public const string VersionAdmob = "https://github.com/googleads/googleads-mobile-unity.git?path=packages/com.google.ads.mobile#v11.0.0"; #region Google Unity public const string PackageNameGGPlayCore = "com.google.play.core"; public const string MaxVersionGGPlayCore = "https://github.com/RageAgainstThePixel/com.google.play.core.git#1.8.5"; public const string PackageNameGGPlayCommon = "com.google.play.common"; public const string MaxVersionGGPlayCommon = "https://github.com/RageAgainstThePixel/com.google.play.common.git#1.9.2"; public const string PackageNameGGExternalDependencyManager = "com.google.external-dependency-manager"; public const string MaxVersionGGExternalDependencyManager = "https://github.com/googlesamples/unity-jar-resolver.git?path=upm#v1.2.187"; public const string PackageNameGGPlayReview = "com.google.play.review"; public const string MaxVersionGGPlayReview = "https://github.com/pancake-llc/in-app-review.git#1.8.3"; #endregion #region Firebase public const string PackageNameFirebaseApp = "com.google.firebase.app"; public const string MaxVersionFirebaseApp = "https://github.com/RageAgainstThePixel/com.google.firebase.app.git#13.10.0"; public const string PackageNameFirebaseRemoteConfig = "com.google.firebase.remote-config"; public const string MaxVersionFirebaseRemoteConfig = "https://github.com/RageAgainstThePixel/com.google.firebase.remote-config.git#13.10.0"; public const string PackageNameFirebaseAnalytics = "com.google.firebase.analytics"; public const string MaxVersionFirebaseAnalytics = "https://github.com/RageAgainstThePixel/com.google.firebase.analytics.git#13.10.0"; public const string PackageNameFirebaseDatabase = "com.google.firebase.database"; public const string MaxVersionFirebaseDatabase = "https://github.com/RageAgainstThePixel/com.google.firebase.database.git#13.10.0"; public const string PackageNameFirebaseAuth = "com.google.firebase.auth"; public const string MaxVersionFirebaseAuth = "https://github.com/RageAgainstThePixel/com.google.firebase.auth.git#13.10.0"; public const string PackageNameFirebaseCrashlytics = "com.google.firebase.crashlytics"; public const string MaxVersionFirebaseCrashlytics = "https://github.com/RageAgainstThePixel/com.google.firebase.crashlytics.git#13.10.0"; #endregion public const string PackageNameAdjust = "com.adjust.sdk"; public const string MaxVersionAdjust = "https://github.com/adjust/unity_sdk.git?path=Assets/Adjust#v5.5.1"; public const string PackageNamePlayFab = "com.pancake.playfab"; public const string MaxVersionPlayFab = "https://github.com/pancake-llc/playfab.git#2.183.231124"; public const string PackageNameAppFlyer = "appsflyer-unity-plugin"; public const string MaxVersionAppFlyer = "https://github.com/AppsFlyerSDK/appsflyer-unity-plugin.git?path=Assets/AppsFlyer#6.17.81"; public const string PackageNameCoffeeUIEffect = "com.coffee.ui-effect"; public const string MaxVersionCoffeeUIEffect = "https://github.com/mob-sakai/UIEffect.git?path=Packages/src#5.10.8"; public const string PackageNameCoffeeUIParticle = "com.coffee.ui-particle"; public const string MaxVersionCoffeeUIParticle = "https://github.com/mob-sakai/ParticleEffectForUGUI.git#4.12.1"; public const string PackageNameAppleSignIn = "com.lupidan.apple-signin-unity"; public const string MaxVersionAppleSignIn = "https://github.com/lupidan/apple-signin-unity.git?path=Source#1.5.0"; #region Spine public const string PackageNameSpineCsharp = "com.esotericsoftware.spine.spine-csharp"; public const string MaxVersionSpineCsharp = "https://github.com/EsotericSoftware/spine-runtimes.git?path=spine-csharp/src#4.1"; public const string PackageNameSpineUnity = "com.esotericsoftware.spine.spine-unity"; public const string MaxVersionSpineUnity = "https://github.com/EsotericSoftware/spine-runtimes.git?path=spine-unity/Assets/Spine#4.1"; #endregion public const string PackageNameUniTask = "com.cysharp.unitask"; public const string MaxVersionUniTask = "https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask#2.5.10"; public const string PackageNameBakingSheet = "com.cathei.bakingsheet"; public const string MaxVersionBakingSheet = "https://github.com/cathei/BakingSheet.git?path=UnityProject/Packages/com.cathei.bakingsheet#v4.1.3"; } } ================================================ FILE: VirtueSky/ControlPanel/ConstantPackage.cs.meta ================================================ fileFormatVersion: 2 guid: a63c47ff7afd4d19a7bf1c5d3c730433 timeCreated: 1704948203 ================================================ FILE: VirtueSky/ControlPanel/ControlPanelWindowEditor.cs ================================================ using UnityEditor; using UnityEngine; namespace VirtueSky.ControlPanel.Editor { public class ControlPanelWindowEditor : EditorWindow { private StatePanelControl statePanelControl; private Vector2 scrollButton = Vector2.zero; private const string keySaveStatePanelControl = "Window_StatePanelControl"; private static StatePanelControl StatePanelControl { get => (StatePanelControl)EditorPrefs.GetInt(keySaveStatePanelControl, (int)StatePanelControl.About); set => EditorPrefs.SetInt(keySaveStatePanelControl, (int)value); } [MenuItem("Sunflower/Magic Panel &1", false, priority = 1)] public static void ShowPanelControlWindow() { ControlPanelWindowEditor window = GetWindow("Magic Panel"); if (window == null) { Debug.LogError("Couldn't open the window!"); return; } window.minSize = new Vector2(600, 300); window.Show(); } private void OnEnable() { statePanelControl = StatePanelControl; CPAdvertisingDrawer.OnEnable(); CPIapDrawer.OnEnable(); CPLevelEditorDrawer.OnEnable(); CPFolderIconDrawer.OnEnable(); CPAdjustDrawer.OnEnable(); CPAppsFlyerDrawer.OnEnable(); CPLocalizationDrawer.OnEnable(); } private void OnDisable() { CPLevelEditorDrawer.OnDisable(); } private void OnGUI() { GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); CPUtility.DrawHeader("Magic Panel", 17); GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); GUILayout.Space(10); Handles.color = Color.black; Handles.DrawAAPolyLine(4, new Vector3(0, 30), new Vector3(position.width, 30)); // GuiLine(2, Color.black); GUILayout.Space(10); GUILayout.BeginHorizontal(); GUILayout.BeginVertical(GUILayout.Width(ConstantControlPanel.WIDTH_CONTENT_BUTTON_STATE_CONTROL_PANEL)); scrollButton = EditorGUILayout.BeginScrollView(scrollButton); DrawButton(); EditorGUILayout.EndScrollView(); Handles.DrawAAPolyLine(4, new Vector3(ConstantControlPanel.POSITION_X_START_CONTENT, 30), new Vector3(ConstantControlPanel.POSITION_X_START_CONTENT, position.height)); GUILayout.EndVertical(); DrawContent(); GUILayout.EndHorizontal(); } void DrawButton() { DrawButtonChooseState("Advertising", StatePanelControl.Advertising); DrawButtonChooseState("In App Purchase", StatePanelControl.InAppPurchase); DrawButtonChooseState("Scriptable Event", StatePanelControl.SO_Event); DrawButtonChooseState("Scriptable Variable", StatePanelControl.SO_Variable); DrawButtonChooseState("Audio", StatePanelControl.Audio); DrawButtonChooseState("Firebase", StatePanelControl.Firebase); DrawButtonChooseState("Adjust", StatePanelControl.Adjust); DrawButtonChooseState("AppsFlyer", StatePanelControl.AppsFlyer); DrawButtonChooseState("Assets Finder", StatePanelControl.AssetsFinder); DrawButtonChooseState("In App Review", StatePanelControl.InAppReview); DrawButtonChooseState("Level Editor", StatePanelControl.LevelEditor); DrawButtonChooseState("Localization", StatePanelControl.Localization); DrawButtonChooseState("Game Service", StatePanelControl.GameService); DrawButtonChooseState("Folder Icon", StatePanelControl.FolderIcon); DrawButtonChooseState("Hierarchy", StatePanelControl.Hierarchy); DrawButtonChooseState("Notifications", StatePanelControl.NotificationsChanel); DrawButtonChooseState("Scripting Define Symbols", StatePanelControl.ScriptDefineSymbols); DrawButtonChooseState("Register Package", StatePanelControl.RegisterPackage); DrawButtonChooseState("Extensions", StatePanelControl.Extensions); DrawButtonChooseState("About", StatePanelControl.About); } void DrawContent() { switch (statePanelControl) { case StatePanelControl.Advertising: CPAdvertisingDrawer.OnDrawAdvertising(); break; case StatePanelControl.InAppPurchase: CPIapDrawer.OnDrawIap(position); break; case StatePanelControl.AssetsFinder: CPAssetFinderDrawer.OnDrawAssetUsageDetector(); break; case StatePanelControl.Audio: CPAudioDrawer.OnDrawAudio(position, this); break; case StatePanelControl.InAppReview: CPInAppReviewDrawer.OnDrawInAppReview(position); break; case StatePanelControl.LevelEditor: CPLevelEditorDrawer.OnDrawLevelEditor(position); break; case StatePanelControl.NotificationsChanel: CPNotificationChanelDrawer.OnDrawNotificationChanel(position); break; case StatePanelControl.SO_Event: CPSoEventDrawer.OnDrawSoEvent(); break; case StatePanelControl.SO_Variable: CPSoVariableDrawer.OnDrawSoVariable(); break; case StatePanelControl.ScriptDefineSymbols: CPScriptingDefineSymbolsDrawer.OnDrawScriptingDefineSymbols(); break; case StatePanelControl.RegisterPackage: CPRegisterPackageDrawer.OnDrawRegisterPackageByManifest(position); break; case StatePanelControl.FolderIcon: CPFolderIconDrawer.OnDrawFolderIcon(); break; case StatePanelControl.Hierarchy: CPHierarchyDrawer.OnDrawQHierarchyEvent(position, this); break; case StatePanelControl.Firebase: CPFirebaseDrawer.OnDrawFirebase(position); break; case StatePanelControl.Localization: CPLocalizationDrawer.OnDrawLocalization(position); break; case StatePanelControl.Adjust: CPAdjustDrawer.OnDrawAdjust(); break; case StatePanelControl.AppsFlyer: CPAppsFlyerDrawer.OnDrawAppsFlyer(); break; case StatePanelControl.GameService: CPGameServiceDrawer.OnDrawGameService(); break; case StatePanelControl.Extensions: CPExtensionsDrawer.OnDrawExtensions(position); break; case StatePanelControl.About: CPAboutDrawer.OnDrawAbout(position); break; } } void DrawButtonChooseState(string title, StatePanelControl _statePanelControlTab) { GUILayout.BeginHorizontal(); GUILayout.Space(5); GUILayout.Box(CPUtility.GetIcon(_statePanelControlTab), GUIStyle.none, GUILayout.ExpandWidth(true), GUILayout.Width(18), GUILayout.Height(18)); bool clicked = GUILayout.Toggle(_statePanelControlTab == statePanelControl, title, GUI.skin.button, GUILayout.ExpandWidth(true), GUILayout.ExpandHeight(true), GUILayout.Height(20)); if (clicked && statePanelControl != _statePanelControlTab) { statePanelControl = _statePanelControlTab; StatePanelControl = statePanelControl; } GUILayout.EndHorizontal(); GUILayout.Space(2); } } public enum StatePanelControl { Advertising = 0, InAppPurchase = 1, AssetsFinder = 2, Audio = 3, InAppReview = 4, LevelEditor = 5, NotificationsChanel = 6, SO_Event = 7, SO_Variable = 8, Adjust = 9, AppsFlyer = 10, ScriptDefineSymbols = 11, RegisterPackage = 12, Hierarchy = 13, FolderIcon = 14, Firebase = 15, GameService = 16, Localization = 17, Extensions = 18, About = 19, } } ================================================ FILE: VirtueSky/ControlPanel/ControlPanelWindowEditor.cs.meta ================================================ fileFormatVersion: 2 guid: dfee25753bfd489e8abaf8774cdcae0a timeCreated: 1704274678 ================================================ FILE: VirtueSky/ControlPanel/Virtuesky.Sunflower.ControlPanel.Editor.asmdef ================================================ { "name": "Virtuesky.Sunflower.ControlPanel.Editor", "rootNamespace": "", "references": [ "GUID:ea1af3c654880af4ca6bb44b012e055e", "GUID:405e8b335a1c8114fb36942b7f97083f", "GUID:8579ab42c9ab63d4bac5fb07bd390b46", "GUID:dcf049c718e6d4d0b8bbcaf56be706c2", "GUID:2e2b9634fb53a4c01af8453caa52e1b4", "GUID:b1979aef4cc42ae46af23ce2c4c109cc", "GUID:8bd745a7d8af04c528da60c6b56aa92a", "GUID:ae37c1f040fc3574a93bca20d91449d9", "GUID:e0f213a0782f8f74b8e336c82c8f43b8", "GUID:c904f6d969e991d459a0843b71c22ec5", "GUID:324caed91501a9c47a04ebfd87b68794", "GUID:32dbaa332e571bf429b7de517f75f074", "GUID:0b6289df6f84a6f4b982ff72d23e0273", "GUID:49674d15b25185649b7ec8ac5d378747", "GUID:abd57f653a468a04c8d4e281527ff293", "GUID:0566ef25681cb4cec8714d50dda26ad1", "GUID:c282fd4f3fc2c7540914e85842a013c7", "GUID:fca7ec166e04dc948b624a983315e2c9", "GUID:2ba9ab3e4292d6e4b81f0022dc854eee", "GUID:ade1d0a32a74d554ab9bf506427a1b1b", "GUID:877be62fd20bbdb489dd86ee21cee87d", "GUID:5e9107a8f2499184ea26564811dda246", "GUID:c7e7793e0b5d326429f90e6fd716775e", "GUID:6a3996cca4c689e4597a79d47ef54353", "GUID:acb3cac55c622ec459c8caadf707623a" ], "includePlatforms": [ "Editor" ], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], "versionDefines": [], "noEngineReferences": false } ================================================ FILE: VirtueSky/ControlPanel/Virtuesky.Sunflower.ControlPanel.Editor.asmdef.meta ================================================ fileFormatVersion: 2 guid: 76b168df9f87b864c9d9ce43f6acd854 AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/ControlPanel.meta ================================================ fileFormatVersion: 2 guid: 17354e00e1ed0484da96acaf3b238c08 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Core/Editor/OptionalPropertyDrawer.cs ================================================ using UnityEditor; using VirtueSky.Core; namespace VirtueSky.CoreEditor { using UnityEngine; [CustomPropertyDrawer(typeof(Optional<>))] public class OptionalPropertyDrawer : PropertyDrawer { public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { var valueProperty = property.FindPropertyRelative("value"); return EditorGUI.GetPropertyHeight(valueProperty); } public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { var valueProperty = property.FindPropertyRelative("value"); var enabledProperty = property.FindPropertyRelative("enabled"); EditorGUI.BeginProperty(position, label, property); position.width -= 24; EditorGUI.BeginDisabledGroup(!enabledProperty.boolValue); EditorGUI.PropertyField(position, valueProperty, label, true); EditorGUI.EndDisabledGroup(); int indent = EditorGUI.indentLevel; EditorGUI.indentLevel = 0; position.x += position.width + 24; position.width = position.height = EditorGUI.GetPropertyHeight(enabledProperty); position.x -= position.width; EditorGUI.PropertyField(position, enabledProperty, GUIContent.none); EditorGUI.indentLevel = indent; EditorGUI.EndProperty(); } } } ================================================ FILE: VirtueSky/Core/Editor/OptionalPropertyDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: 2d8179426da74b03ae16a1eda240e031 timeCreated: 1729237567 ================================================ FILE: VirtueSky/Core/Editor/VirtueSky.Sunflower.Core.Editor.asmdef ================================================ { "name": "VirtueSky.Sunflower.Core.Editor", "rootNamespace": "", "references": [ "GUID:acb3cac55c622ec459c8caadf707623a" ], "includePlatforms": [ "Editor" ], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], "versionDefines": [], "noEngineReferences": false } ================================================ FILE: VirtueSky/Core/Editor/VirtueSky.Sunflower.Core.Editor.asmdef.meta ================================================ fileFormatVersion: 2 guid: a62c674bc349edb45a02c380d4339bac AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Core/Editor.meta ================================================ fileFormatVersion: 2 guid: 52d693025a653de41af12018e2396553 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Core/Runtime/App.cs ================================================ using System; using System.Collections; using UnityEngine; using UnityEngine.Internal; namespace VirtueSky.Core { public struct App { private static MonoGlobal _monoGlobal; public static void InitMonoGlobalComponent(MonoGlobal monoGlobal) { App._monoGlobal = monoGlobal; } public static void AddPauseCallback(Action callback) { _monoGlobal.OnGamePause -= callback; _monoGlobal.OnGamePause += callback; } public static void RemovePauseCallback(Action callback) { _monoGlobal.OnGamePause -= callback; } public static void AddFocusCallback(Action callback) { _monoGlobal.OnGameFocus -= callback; _monoGlobal.OnGameFocus += callback; } public static void RemoveFocusCallback(Action callback) { _monoGlobal.OnGameFocus -= callback; } public static void AddQuitCallback(Action callback) { _monoGlobal.OnGameQuit -= callback; _monoGlobal.OnGameQuit += callback; } public static void RemoveQuitCallback(Action callback) { _monoGlobal.OnGameQuit -= callback; } #region Update internal static void SubTick(IEntity tick) { _monoGlobal.AddTick(tick); } public static void SubTick(Action action) { _monoGlobal.AddTick(action); } internal static void SubFixedTick(IEntity fixedTick) { _monoGlobal.AddFixedTick(fixedTick); } public static void SubFixedTick(Action action) { _monoGlobal.AddFixedTick(action); } internal static void SubLateTick(IEntity lateTick) { _monoGlobal.AddLateTick(lateTick); } public static void SubLateTick(Action action) { _monoGlobal.AddLateTick(action); } internal static void UnSubTick(IEntity tick) { _monoGlobal.RemoveTick(tick); } public static void UnSubTick(Action action) { _monoGlobal.RemoveTick(action); } internal static void UnSubFixedTick(IEntity fixedTick) { _monoGlobal.RemoveFixedTick(fixedTick); } public static void UnSubFixedTick(Action action) { _monoGlobal.RemoveFixedTick(action); } internal static void UnSubLateTick(IEntity lateTick) { _monoGlobal.RemoveLateTick(lateTick); } public static void UnSubLateTick(Action action) { _monoGlobal.RemoveLateTick(action); } #endregion #region DelayHandle /// /// Delay call /// /// The duration to wait before the DelayHandle fires. /// The action to run when the DelayHandle elapses. /// A function to call each tick of the DelayHandle. Takes the number of seconds elapsed since /// the start of the current cycle. /// Whether the DelayHandle should restart after executing. /// Whether the DelayHandle uses real-time(not affected by slow-mo or pausing) or /// game-time(affected by time scale changes). /// public static DelayHandle Delay(float duration, Action onComplete, Action onUpdate = null, bool isLooped = false, bool useRealTime = false) { var timer = new DelayHandle(duration, onComplete, onUpdate, isLooped, useRealTime, null); _monoGlobal.RegisterDelayHandle(timer); return timer; } /// /// Safe Delay call when it had target, progress delay will be cancel when target was destroyed /// /// The duration to wait before the DelayHandle fires. /// The action to run when the DelayHandle elapses. /// A function to call each tick of the DelayHandle. Takes the number of seconds elapsed since /// the start of the current cycle. /// Whether the DelayHandle should restart after executing. /// Whether the DelayHandle uses real-time(not affected by slow-mo or pausing) or /// game-time(affected by time scale changes). /// The target (behaviour) to attach this DelayHandle to. public static DelayHandle Delay( MonoBehaviour target, float duration, Action onComplete, Action onUpdate = null, bool isLooped = false, bool useRealTime = false) { var timer = new DelayHandle(duration, onComplete, onUpdate, isLooped, useRealTime, target); _monoGlobal.RegisterDelayHandle(timer); return timer; } public static void CancelDelay(DelayHandle delayHandle) { delayHandle?.Cancel(); } public static void PauseDelay(DelayHandle delayHandle) { delayHandle?.Pause(); } public static void ResumeDelay(DelayHandle delayHandle) { delayHandle?.Resume(); } public static void CancelAllDelay() { _monoGlobal.CancelAllDelayHandle(); } public static void PauseAllDelay() { _monoGlobal.PauseAllDelayHandle(); } public static void ResumeAllDelay() { _monoGlobal.ResumeAllDelayHandle(); } #endregion #region Effective [System.Runtime.CompilerServices.MethodImpl( System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public static Coroutine StartCoroutine(IEnumerator routine) => _monoGlobal.StartCoroutineImpl(routine); [System.Runtime.CompilerServices.MethodImpl( System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public static Coroutine StartCoroutine(string methodName, [DefaultValue("null")] object value) => _monoGlobal.StartCoroutineImpl(methodName, value); [System.Runtime.CompilerServices.MethodImpl( System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public static Coroutine StartCoroutine(string methodName) => _monoGlobal.StartCoroutineImpl(methodName); [System.Runtime.CompilerServices.MethodImpl( System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public static void StopCoroutine(IEnumerator routine) => _monoGlobal.StopCoroutineImpl(routine); [System.Runtime.CompilerServices.MethodImpl( System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public static void StopCoroutine(Coroutine routine) => _monoGlobal.StopCoroutineImpl(routine); [System.Runtime.CompilerServices.MethodImpl( System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public static void StopCoroutine(string methodName) => _monoGlobal.StopCoroutineImpl(methodName); [System.Runtime.CompilerServices.MethodImpl( System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public static void StopAllCoroutine() => _monoGlobal.StopAllCoroutinesImpl(); [System.Runtime.CompilerServices.MethodImpl( System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public static Action ToMainThread(Action action) => _monoGlobal.ToMainThreadImpl(action); [System.Runtime.CompilerServices.MethodImpl( System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public static Action ToMainThread(Action action) => _monoGlobal.ToMainThreadImpl(action); [System.Runtime.CompilerServices.MethodImpl( System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public static Action ToMainThread(Action action) => _monoGlobal.ToMainThreadImpl(action); [System.Runtime.CompilerServices.MethodImpl( System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public static Action ToMainThread(Action action) => _monoGlobal.ToMainThreadImpl(action); [System.Runtime.CompilerServices.MethodImpl( System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public static void RunOnMainThread(Action action) => _monoGlobal.RunOnMainThreadImpl(action); #endregion } } ================================================ FILE: VirtueSky/Core/Runtime/App.cs.meta ================================================ fileFormatVersion: 2 guid: 04501404729040cf9c419e7c25c26f06 timeCreated: 1696306333 ================================================ FILE: VirtueSky/Core/Runtime/BaseMono.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Core { [EditorIcon("icon_csharp")] public class BaseMono : MonoBehaviour, IEntity { public virtual void OnEnable() { SubTick(); } public virtual void OnDisable() { UnSubTick(); } public virtual void Initialize() { } public virtual void Tick() { } public virtual void LateTick() { } public virtual void FixedTick() { } public virtual void CleanUp() { } void SubTick() { App.SubTick(this); App.SubLateTick(this); App.SubFixedTick(this); } void UnSubTick() { App.UnSubTick(this); App.UnSubLateTick(this); App.UnSubFixedTick(this); } } } ================================================ FILE: VirtueSky/Core/Runtime/BaseMono.cs.meta ================================================ fileFormatVersion: 2 guid: d730116726f0ce342bfe91266ac72fdf MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Core/Runtime/BaseSO.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Core { public class BaseSO : ScriptableObject, IEntity { [GUIColor(0.8f, 1.0f, 0.6f), Space(10), SerializeField, TextArea(2, 5)] private string description; public void Enable() { SubTick(); } public void Disable() { UnSubTick(); } void SubTick() { App.SubTick(this); App.SubLateTick(this); App.SubFixedTick(this); } public virtual void Initialize() { } public virtual void Tick() { } public virtual void LateTick() { } public virtual void FixedTick() { } public virtual void CleanUp() { } public virtual void Destroy() { } void UnSubTick() { App.UnSubTick(this); App.UnSubLateTick(this); App.UnSubFixedTick(this); } } } ================================================ FILE: VirtueSky/Core/Runtime/BaseSO.cs.meta ================================================ fileFormatVersion: 2 guid: 8e70f299e69a94d48863d0a992365d4f MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Core/Runtime/CacheComponent.cs ================================================ using UnityEngine; namespace VirtueSky.Core { public class CacheComponent : BaseMono { public T component; public Transform CacheTransform { get; private set; } protected virtual void Awake() { if (CacheTransform == null) CacheTransform = transform; GetCacheComponent(); } void GetCacheComponent() { if (component == null) { component = GetComponent(); } } #if UNITY_EDITOR protected virtual void Reset() { GetCacheComponent(); } #endif } } ================================================ FILE: VirtueSky/Core/Runtime/CacheComponent.cs.meta ================================================ fileFormatVersion: 2 guid: 5a85bc3831bb51b4aa481a822db6e50d MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Core/Runtime/DelayHandle.cs ================================================ using System; using UnityEngine; namespace VirtueSky.Core { public class DelayHandle { /// /// How long the timer takes to complete from start to finish. /// public float Duration { get; private set; } /// /// Whether the timer will run again after completion. /// public bool IsLooped { get; set; } /// /// Whether or not the timer completed running. This is false if the timer was cancelled. /// public bool IsCompleted { get; private set; } /// /// Whether the timer uses real-time or game-time. Real time is unaffected by changes to the timescale /// of the game(e.g. pausing, slow-mo), while game time is affected. /// public bool UsesRealTime { get; private set; } /// /// Whether the timer is currently paused. /// public bool IsPaused => _timeElapsedBeforePause.HasValue; /// /// Whether or not the timer was cancelled. /// public bool IsCancelled => _timeElapsedBeforeCancel.HasValue; /// /// Get whether or not the timer has finished running for any reason. /// public bool IsDone => IsCompleted || IsCancelled || IsOwnerDestroyed; private bool IsOwnerDestroyed => _hasAutoDestroyOwner && _autoDestroyOwner == null; private readonly Action _onComplete; private readonly Action _onUpdate; private float _startTime; private float _lastUpdateTime; // for pausing, we push the start time forward by the amount of time that has passed. // this will mess with the amount of time that elapsed when we're cancelled or paused if we just // check the start time versus the current world time, so we need to cache the time that was elapsed // before we paused/cancelled private float? _timeElapsedBeforeCancel; private float? _timeElapsedBeforePause; // after the auto destroy owner is destroyed, the timer will expire // this way you don't run into any annoying bugs with timers running and accessing objects // after they have been destroyed private readonly MonoBehaviour _autoDestroyOwner; private readonly bool _hasAutoDestroyOwner; /// /// Stop a timer that is in-progress or paused. The timer's on completion callback will not be called. /// public void Cancel() { if (IsDone) { return; } _timeElapsedBeforeCancel = GetTimeElapsed(); _timeElapsedBeforePause = null; } /// /// Pause a running timer. A paused timer can be resumed from the same point it was paused. /// public void Pause() { if (IsPaused || IsDone) { return; } _timeElapsedBeforePause = GetTimeElapsed(); } /// /// Continue a paused timer. Does nothing if the timer has not been paused. /// public void Resume() { if (!IsPaused || IsDone) { return; } _timeElapsedBeforePause = null; } /// /// Get how many seconds have elapsed since the start of this timer's current cycle. /// /// The number of seconds that have elapsed since the start of this timer's current cycle, i.e. /// the current loop if the timer is looped, or the start if it isn't. /// /// If the timer has finished running, this is equal to the duration. /// /// If the timer was cancelled/paused, this is equal to the number of seconds that passed between the timer /// starting and when it was cancelled/paused. public float GetTimeElapsed() { if (IsCompleted || GetWorldTime() >= GetFireTime()) { return Duration; } return _timeElapsedBeforeCancel ?? _timeElapsedBeforePause ?? GetWorldTime() - _startTime; } /// /// Get how many seconds remain before the timer completes. /// /// The number of seconds that remain to be elapsed until the timer is completed. A timer /// is only elapsing time if it is not paused, cancelled, or completed. This will be equal to zero /// if the timer completed. public float GetTimeRemaining() { return Duration - GetTimeElapsed(); } /// /// Get how much progress the timer has made from start to finish as a ratio. /// /// A value from 0 to 1 indicating how much of the timer's duration has been elapsed. public float GetRatioComplete() { return GetTimeElapsed() / Duration; } /// /// Get how much progress the timer has left to make as a ratio. /// /// A value from 0 to 1 indicating how much of the timer's duration remains to be elapsed. public float GetRatioRemaining() { return GetTimeRemaining() / Duration; } internal DelayHandle(float duration, Action onComplete, Action onUpdate, bool isLooped, bool usesRealTime, MonoBehaviour autoDestroyOwner) { Duration = duration; _onComplete = onComplete; _onUpdate = onUpdate; IsLooped = isLooped; UsesRealTime = usesRealTime; _autoDestroyOwner = autoDestroyOwner; _hasAutoDestroyOwner = autoDestroyOwner != null; _startTime = GetWorldTime(); _lastUpdateTime = _startTime; } private float GetWorldTime() { return UsesRealTime ? Time.realtimeSinceStartup : Time.time; } private float GetFireTime() { return _startTime + Duration; } private float GetTimeDelta() { return GetWorldTime() - _lastUpdateTime; } internal void Update() { if (IsDone) return; if (IsPaused) { _startTime += GetTimeDelta(); _lastUpdateTime = GetWorldTime(); return; } _lastUpdateTime = GetWorldTime(); _onUpdate?.Invoke(GetTimeElapsed()); if (GetWorldTime() >= GetFireTime()) { _onComplete?.Invoke(); if (IsLooped) _startTime = GetWorldTime(); else IsCompleted = true; } } } } ================================================ FILE: VirtueSky/Core/Runtime/DelayHandle.cs.meta ================================================ fileFormatVersion: 2 guid: 7ccbac69e48a48b08e59b9ec4fff3c4b timeCreated: 1711449985 ================================================ FILE: VirtueSky/Core/Runtime/IEntity.cs ================================================ namespace VirtueSky.Core { public interface IEntity { void Initialize(); void Tick(); void LateTick(); void FixedTick(); void CleanUp(); } } ================================================ FILE: VirtueSky/Core/Runtime/IEntity.cs.meta ================================================ fileFormatVersion: 2 guid: ef029fe4bbaf08c458fe914d4788a11e MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Core/Runtime/MonoGlobal.cs ================================================ using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Internal; using VirtueSky.DataStorage; using VirtueSky.Inspector; namespace VirtueSky.Core { [EditorIcon("icon_csharp")] public class MonoGlobal : MonoBehaviour { private readonly List _toMainThreads = new(); private volatile bool _isToMainThreadQueueEmpty = true; private List _localToMainThreads = new(); internal event Action OnGamePause; internal event Action OnGameQuit; internal event Action OnGameFocus; internal event Action OnTick; internal event Action OnFixedTick; internal event Action OnLateTick; #region Sub / UnSub For Update Procresses internal void AddTick(IEntity tick) { OnTick += tick.Tick; } internal void AddTick(Action action) { OnTick += action; } internal void AddFixedTick(IEntity fixedTick) { OnFixedTick += fixedTick.FixedTick; } internal void AddFixedTick(Action action) { OnFixedTick += action; } internal void AddLateTick(IEntity lateTick) { OnLateTick += lateTick.LateTick; } internal void AddLateTick(Action action) { OnLateTick += action; } internal void RemoveTick(IEntity tick) { OnTick -= tick.Tick; } internal void RemoveTick(Action action) { OnTick -= action; } internal void RemoveFixedTick(IEntity fixedTick) { OnFixedTick -= fixedTick.FixedTick; } internal void RemoveFixedTick(Action action) { OnFixedTick -= action; } internal void RemoveLateTick(IEntity lateTick) { OnLateTick -= lateTick.LateTick; } internal void RemoveLateTick(Action action) { OnLateTick -= action; } #endregion #region Update Handle private void Update() { OnTick?.Invoke(); UpdateAllDelayHandle(); if (_isToMainThreadQueueEmpty) return; _localToMainThreads.Clear(); lock (_toMainThreads) { for (var i = 0; i < _toMainThreads.Count; i++) { _localToMainThreads.Add(_toMainThreads[i]); } _toMainThreads.Clear(); _isToMainThreadQueueEmpty = true; } for (int i = 0; i < _localToMainThreads.Count; i++) { _localToMainThreads[i].Invoke(); } } private void FixedUpdate() { OnFixedTick?.Invoke(); } private void LateUpdate() { OnLateTick?.Invoke(); } #endregion #region App Handle private void OnApplicationFocus(bool hasFocus) { OnGameFocus?.Invoke(hasFocus); } private void OnApplicationPause(bool pauseStatus) { OnGamePause?.Invoke(pauseStatus); if (pauseStatus && GameData.IsAutoSave) { GameData.Save(); } } private void OnApplicationQuit() { OnGameQuit?.Invoke(); if (GameData.IsAutoSave) { GameData.Save(); } } #endregion #region delay handle private List _timers = new(); // buffer adding timers so we don't edit a collection during iteration private List _timersToAdd = new(); //private int _fixedFrameCount; internal void RegisterDelayHandle(DelayHandle delayHandle) { _timersToAdd.Add(delayHandle); } internal void CancelAllDelayHandle() { for (var i = 0; i < _timers.Count; i++) { _timers[i].Cancel(); } _timers = new List(); _timersToAdd = new List(); } internal void PauseAllDelayHandle() { for (var i = 0; i < _timers.Count; i++) { _timers[i].Pause(); } } internal void ResumeAllDelayHandle() { for (var i = 0; i < _timers.Count; i++) { _timers[i].Resume(); } } private void UpdateAllDelayHandle() { if (_timersToAdd.Count > 0) { for (var i = 0; i < _timersToAdd.Count; i++) { _timers.Add(_timersToAdd[i]); } _timersToAdd.Clear(); } for (var i = 0; i < _timers.Count; i++) { _timers[i].Update(); } _timers.RemoveAll(t => t.IsDone); } #endregion #region Effective internal Coroutine StartCoroutineImpl(IEnumerator routine) { if (routine != null) { return StartCoroutine(routine); } return null; } internal Coroutine StartCoroutineImpl(string methodName, [DefaultValue("null")] object value) { if (!string.IsNullOrEmpty(methodName)) { return StartCoroutine(methodName, value); } return null; } internal Coroutine StartCoroutineImpl(string methodName) { if (!string.IsNullOrEmpty(methodName)) { return StartCoroutine(methodName); } return null; } internal void StopCoroutineImpl(IEnumerator routine) { if (routine != null) StopCoroutine(routine); } internal void StopCoroutineImpl(Coroutine routine) { if (routine != null) StopCoroutine(routine); } internal void StopCoroutineImpl(string methodName) { if (!string.IsNullOrEmpty(methodName)) { StopCoroutine(methodName); } } internal void StopAllCoroutinesImpl() { StopAllCoroutines(); } /// /// Schedules the specifies action to be run on the main thread (game thread). /// The action will be invoked upon the next Unity Update event. /// /// Action. internal void RunOnMainThreadImpl(Action action) { lock (_toMainThreads) { _toMainThreads.Add(action); _isToMainThreadQueueEmpty = false; } } /// /// Converts the specified action to one that runs on the main thread. /// The converted action will be invoked upon the next Unity Update event. /// /// The main thread. /// Act. internal Action ToMainThreadImpl(Action action) { if (action == null) return delegate { }; return () => RunOnMainThreadImpl(action); } /// /// Converts the specified action to one that runs on the main thread. /// The converted action will be invoked upon the next Unity Update event. /// /// The main thread. /// Act. /// The 1st type parameter. internal Action ToMainThreadImpl(Action action) { if (action == null) return delegate { }; return (arg) => RunOnMainThreadImpl(() => action(arg)); } /// /// Converts the specified action to one that runs on the main thread. /// The converted action will be invoked upon the next Unity Update event. /// /// The main thread. /// Act. /// The 1st type parameter. /// The 2nd type parameter. internal Action ToMainThreadImpl(Action action) { if (action == null) return delegate { }; return (arg1, arg2) => RunOnMainThreadImpl(() => action(arg1, arg2)); } /// /// Converts the specified action to one that runs on the main thread. /// The converted action will be invoked upon the next Unity Update event. /// /// The main thread. /// Act. /// The 1st type parameter. /// The 2nd type parameter. /// The 3rd type parameter. internal Action ToMainThreadImpl(Action action) { if (action == null) return delegate { }; return (arg1, arg2, arg3) => RunOnMainThreadImpl(() => action(arg1, arg2, arg3)); } #endregion } } ================================================ FILE: VirtueSky/Core/Runtime/MonoGlobal.cs.meta ================================================ fileFormatVersion: 2 guid: b35e41f4eb7743208efa75519c589e87 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Core/Runtime/Optional.cs ================================================ using System; using UnityEngine; namespace VirtueSky.Core { [Serializable] public struct Optional { [SerializeField] private bool enabled; [SerializeField] private T value; public bool Enabled => enabled; public T Value => value; public Optional(T value) : this() { enabled = true; this.value = value; } public Optional(bool enabled, T value) { this.enabled = enabled; this.value = value; } public static implicit operator Optional(T v) { return new Optional(v); } public static implicit operator T(Optional o) { return o.Value; } public static implicit operator bool(Optional o) { return o.enabled; } public static bool operator ==(Optional lhs, Optional rhs) { if (lhs.Value is null) return rhs.Value is null; return lhs.Value.Equals(rhs.Value); } public static bool operator !=(Optional lhs, Optional rhs) { return !(lhs == rhs); } public override bool Equals(object obj) { if (Value is null) return obj is null; return Value.Equals(obj); } public override int GetHashCode() { return Value.GetHashCode(); } public override string ToString() { return Value.ToString(); } } } ================================================ FILE: VirtueSky/Core/Runtime/Optional.cs.meta ================================================ fileFormatVersion: 2 guid: e10115a70c8348a5a8eb3852528c7702 timeCreated: 1729158369 ================================================ FILE: VirtueSky/Core/Runtime/RuntimeInitialize.cs ================================================ using UnityEngine; using VirtueSky.DataStorage; namespace VirtueSky.Core { public class RuntimeInitialize { [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] private static void AutoInitialize() { var app = new GameObject("MonoGlobal"); App.InitMonoGlobalComponent(app.AddComponent()); GameData.Init(); Object.DontDestroyOnLoad(app); } } } ================================================ FILE: VirtueSky/Core/Runtime/RuntimeInitialize.cs.meta ================================================ fileFormatVersion: 2 guid: 2934229b05d34a618ea9472220392439 timeCreated: 1695109832 ================================================ FILE: VirtueSky/Core/Runtime/UnityServiceInitialization.cs ================================================ #if VIRTUESKY_UNITY_SERVICES using Unity.Services.Core; using Unity.Services.Core.Environments; #endif using UnityEngine; namespace VirtueSky.Core { public class UnityServiceInitialization : MonoBehaviour { private enum Environment { Production, Development, } [SerializeField] private Environment environment = Environment.Production; public static bool IsUnityServiceReady { get; private set; } private void Awake() { Init(); } private async void Init() { #if VIRTUESKY_UNITY_SERVICES IsUnityServiceReady = false; var options = new InitializationOptions(); options.SetEnvironmentName(environment.ToString().ToLower()); await UnityServices.InitializeAsync(options); IsUnityServiceReady = true; #endif } } } ================================================ FILE: VirtueSky/Core/Runtime/UnityServiceInitialization.cs.meta ================================================ fileFormatVersion: 2 guid: cc3bfe5d4d6342a28dc707cf2416ee41 timeCreated: 1734073870 ================================================ FILE: VirtueSky/Core/Runtime/virtuesky.sunflower.core.asmdef ================================================ { "name": "Virtuesky.Sunflower.Core", "rootNamespace": "", "references": [ "GUID:32dbaa332e571bf429b7de517f75f074", "GUID:324caed91501a9c47a04ebfd87b68794", "GUID:fe25561d224ed4743af4c60938a59d0b", "GUID:70ea675efa2644cef98c7ece24158333" ], "includePlatforms": [], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], "versionDefines": [], "noEngineReferences": false } ================================================ FILE: VirtueSky/Core/Runtime/virtuesky.sunflower.core.asmdef.meta ================================================ fileFormatVersion: 2 guid: acb3cac55c622ec459c8caadf707623a AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Core/Runtime.meta ================================================ fileFormatVersion: 2 guid: aaf872875f30d65418f32602e058c14e folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Core.meta ================================================ fileFormatVersion: 2 guid: 0ad9f466005576c409d885df4181be0e folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/DataStorage/Editor/DataWindowEditor.cs ================================================ using UnityEditor; using UnityEngine; using VirtueSky.Misc; using VirtueSky.UtilsEditor; namespace VirtueSky.DataStorage { #if UNITY_EDITOR public class DataWindowEditor : EditorWindow { [MenuItem("Sunflower/Clear All Data", priority = 501)] public static void ClearAllData() { GameData.DeleteAll(); GameData.DeleteFileData(); PlayerPrefs.DeleteAll(); Debug.Log($"Clear all data succeed".SetColor(Color.green)); } [MenuItem("Sunflower/Save Data", priority = 504)] public static void SaveData() { GameData.Save(); Debug.Log($"Save data succeed".SetColor(Color.green)); } [MenuItem("Sunflower/Clear Path Data", priority = 502)] public static void ClearSunDataPath() { GameData.DeleteAll(); GameData.DeleteFileData(); Debug.Log($"Clear sun path data succeed".SetColor(Color.green)); } [MenuItem("Sunflower/Open Path Data", priority = 503)] public static void OpenSunPathData() { string path = GameData.GetPersistentDataPath(); switch (SystemInfo.operatingSystemFamily) { case OperatingSystemFamily.Windows: FileExtension.OpenFolderInExplorer(path); break; case OperatingSystemFamily.MacOSX: FileExtension.OpenFolderInFinder(path); break; } } } #endif } ================================================ FILE: VirtueSky/DataStorage/Editor/DataWindowEditor.cs.meta ================================================ fileFormatVersion: 2 guid: c5c23c930aa10314cb0e5a542e6e0ba0 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/DataStorage/Editor/Virtuesky.Sunflower.DataStorage.Editor.asmdef ================================================ { "name": "Virtuesky.Sunflower.DataStorage.Editor", "rootNamespace": "", "references": [ "GUID:32dbaa332e571bf429b7de517f75f074", "GUID:324caed91501a9c47a04ebfd87b68794", "GUID:c904f6d969e991d459a0843b71c22ec5", "GUID:fca7ec166e04dc948b624a983315e2c9", "GUID:c282fd4f3fc2c7540914e85842a013c7" ], "includePlatforms": [ "Editor" ], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], "versionDefines": [], "noEngineReferences": false } ================================================ FILE: VirtueSky/DataStorage/Editor/Virtuesky.Sunflower.DataStorage.Editor.asmdef.meta ================================================ fileFormatVersion: 2 guid: 0b6289df6f84a6f4b982ff72d23e0273 AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/DataStorage/Editor.meta ================================================ fileFormatVersion: 2 guid: bfa5a0f266824bc45b9bdb52f45ff7e8 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/DataStorage/Runtime/GameData.cs ================================================ using System; using System.Collections.Generic; using System.IO; using System.Runtime.CompilerServices; using UnityEngine; namespace VirtueSky.DataStorage { public static class GameData { private static bool isInitialized; private static int profile; private static Dictionary datas = new(); private const int INIT_SIZE = 64; public static bool IsAutoSave { get; set; } = true; public static event Action OnSaveEvent; #region Internal Stuff [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Init() { if (isInitialized) return; isInitialized = true; Load(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static byte[] Serialize(T data) { return SerializeAdapter.ToBinary(data); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static T Deserialize(byte[] bytes) { return SerializeAdapter.FromBinary(bytes); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void RequireNullCheck() { if (datas == null) Load(); if (datas == null) throw new NullReferenceException(); } private static string GetPath => GetDataPath($"data_{profile}.sun"); static string GetDataPath(string name) { var persistentDataPath = GetPersistentDataPath(); if (!Directory.Exists(persistentDataPath)) { Directory.CreateDirectory(persistentDataPath); } return Path.Combine(persistentDataPath, name); } public static string GetPersistentDataPath() { #if UNITY_EDITOR return Path.Combine(Directory.GetParent(Application.dataPath).FullName, "TempDataStorage"); #else return Application.persistentDataPath; #endif } #endregion #region Public API public static bool IsInitialized => isInitialized; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ChangeProfile(int profile) { if (GameData.profile == profile) return; Save(); GameData.profile = profile; Load(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool VerifyProfile(int profile) { return GameData.profile == profile; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Save() { OnSaveEvent?.Invoke(); byte[] bytes = Serialize(datas); File.WriteAllBytes(GetPath, bytes); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static async void SaveAsync() { OnSaveEvent?.Invoke(); byte[] bytes = Serialize(datas); await File.WriteAllBytesAsync(GetPath, bytes); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Load() { if (!File.Exists(GetPath)) { var stream = File.Create(GetPath); stream.Close(); } byte[] bytes = File.ReadAllBytes(GetPath); if (bytes.Length == 0) { datas.Clear(); return; } datas = Deserialize>(bytes) ?? new Dictionary(INIT_SIZE); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static async void LoadAsync() { if (!File.Exists(GetPath)) { var stream = File.Create(GetPath); stream.Close(); } byte[] bytes = await File.ReadAllBytesAsync(GetPath); if (bytes.Length == 0) { datas.Clear(); return; } datas = Deserialize>(bytes) ?? new Dictionary(INIT_SIZE); } /// /// /// /// /// If value of can not be found or empty! will return the default value of data type! /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static T Get(string key, T @default = default) { RequireNullCheck(); datas.TryGetValue(key, out byte[] value); if (value == null || value.Length == 0) return @default; return Deserialize(value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TryGet(string key, out T data) { RequireNullCheck(); bool hasKey; if (datas.TryGetValue(key, out byte[] value)) { data = Deserialize(value); hasKey = true; } else { data = default; hasKey = false; } return hasKey; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Set(string key, T data) { RequireNullCheck(); byte[] bytes = Serialize(data); if (datas.TryAdd(key, bytes)) return; datas[key] = bytes; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool HasKey(string key) => datas.ContainsKey(key); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void DeleteKey(string key) => datas.Remove(key); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void DeleteAll() => datas.Clear(); public static void DeleteFileData() { if (File.Exists(GetPath)) { File.Delete(GetPath); } } /// /// Get raw byte[] of all data of profile /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte[] Backup() { return SerializeAdapter.ToBinary(datas); } /// /// Load from byte[] /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Restore(byte[] bytes) { datas = SerializeAdapter.FromBinary>(bytes); } #endregion } } ================================================ FILE: VirtueSky/DataStorage/Runtime/GameData.cs.meta ================================================ fileFormatVersion: 2 guid: 2c2791a2d0e74b7eb99e7f60a5c321a6 timeCreated: 1708533098 ================================================ FILE: VirtueSky/DataStorage/Runtime/SerializeAdapter.cs ================================================ using System.Collections.Generic; using System.Linq; using Unity.Collections; using Unity.Collections.LowLevel.Unsafe; using Unity.Collections.LowLevel.Unsafe.NotBurstCompatible; using Unity.Serialization.Binary; namespace VirtueSky.DataStorage { public static class SerializeAdapter { /// /// Serializes the object to binary using the provided adapters. /// Adapters provide control over how serialization is processed. /// /// /// /// /// public static unsafe byte[] ToBinary(T obj, IReadOnlyList adapters = null) { var buffer = new UnsafeAppendBuffer(16, 8, Allocator.Temp); var parameters = new BinarySerializationParameters { UserDefinedAdapters = adapters?.ToList() }; BinarySerialization.ToBinary(&buffer, obj, parameters); byte[] bytes = buffer.ToBytesNBC(); buffer.Dispose(); return bytes; } /// /// Attemtps to deserialize a byte[] to the specified type using the provided adapters. /// /// /// /// /// public static unsafe T FromBinary(byte[] serializedBytes, IReadOnlyList adapters = null) { fixed (byte* ptr = serializedBytes) { var bufferReader = new UnsafeAppendBuffer.Reader(ptr, serializedBytes.Length); var parameters = new BinarySerializationParameters { UserDefinedAdapters = adapters?.ToList() }; return BinarySerialization.FromBinary(&bufferReader, parameters); } } } } ================================================ FILE: VirtueSky/DataStorage/Runtime/SerializeAdapter.cs.meta ================================================ fileFormatVersion: 2 guid: d3289620c19f8444c92a482f8160889e MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/DataStorage/Runtime/Virtuesky.Sunflower.DataStorage.asmdef ================================================ { "name": "Virtuesky.Sunflower.DataStorage", "rootNamespace": "", "references": [ "GUID:c282fd4f3fc2c7540914e85842a013c7", "GUID:2765e68924a08a94ea0ea66b31c0168f", "GUID:e0cd26848372d4e5c891c569017e11f1" ], "includePlatforms": [], "excludePlatforms": [], "allowUnsafeCode": true, "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], "versionDefines": [ { "name": "com.unity.serialization", "expression": "3.1.1", "define": "UNITY_SERIALIZATION" }, { "name": "com.unity.collections", "expression": "2.1.4", "define": "UNITY_SERIALIZATION" } ], "noEngineReferences": false } ================================================ FILE: VirtueSky/DataStorage/Runtime/Virtuesky.Sunflower.DataStorage.asmdef.meta ================================================ fileFormatVersion: 2 guid: 32dbaa332e571bf429b7de517f75f074 AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/DataStorage/Runtime.meta ================================================ fileFormatVersion: 2 guid: f50e6e7f3b71a1a46b9e1f8dc21804c1 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/DataStorage.meta ================================================ fileFormatVersion: 2 guid: 791968b3b56ca3946a6a7051703192c5 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/DataType/DictionaryCustom.cs ================================================ using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.DataType { [Serializable] public class DictionaryCustom : ISerializationCallbackReceiver, IDictionary, IDictionary { [TableList, SerializeField] private List> dictionaryData = new List>(); [NonSerialized] private Dictionary m_dict = new Dictionary(); public Dictionary GetDict => m_dict; public void OnAfterDeserialize() { UpdateDict(); } public void OnBeforeSerialize() { if (!Application.isPlaying) return; UpdateList(); } private void UpdateDict() { if (dictionaryData is { Count: > 0 }) { if (m_dict is { Count: > 0 }) { m_dict.Clear(); } foreach (var data in dictionaryData) { if (data.key != null && data.value != null) { m_dict[data.key] = data.value; } } } } private void UpdateList() { dictionaryData.Clear(); if (m_dict is { Count: > 0 }) { foreach (var kvp in m_dict) { dictionaryData.Add(new DictionaryCustomData(kvp.Key, kvp.Value)); } } } public void Add(object key, object value) { m_dict.Add((TKey)key, (TValue)value); UpdateList(); } public void Add(KeyValuePair item) { m_dict.Add(item.Key, item.Value); UpdateList(); } void ICollection>.Clear() { m_dict.Clear(); } public bool Contains(KeyValuePair item) { return ((IDictionary)m_dict).Contains((TKey)item.Key); } public void CopyTo(KeyValuePair[] array, int arrayIndex) { ((IDictionary)m_dict).CopyTo(array, arrayIndex); } public bool Remove(KeyValuePair item) { var result = ((IDictionary)m_dict).Remove(item); if (result) UpdateList(); return result; } public int Count => m_dict.Count; public bool IsReadOnly => ((IDictionary)m_dict).IsReadOnly; void IDictionary.Clear() { ((IDictionary)m_dict).Clear(); } public bool Contains(object key) { return ((IDictionary)m_dict).Contains((KeyValuePair)key); } IEnumerator> IEnumerable>.GetEnumerator() { return ((IDictionary)m_dict).GetEnumerator(); } IDictionaryEnumerator IDictionary.GetEnumerator() { return ((IDictionary)m_dict).GetEnumerator(); } public void Remove(object key) { m_dict.Remove((TKey)key); UpdateList(); } public bool IsFixedSize => ((IDictionary)m_dict).IsFixedSize; public object this[object key] { get => ((IDictionary)m_dict)[key]; set => ((IDictionary)m_dict)[key] = value; } ICollection IDictionary.Keys => ((IDictionary)m_dict).Keys; ICollection IDictionary.Values => (ICollection)((IDictionary)m_dict).Values; ICollection IDictionary.Keys => (ICollection)((IDictionary)m_dict).Keys; ICollection IDictionary.Values => ((IDictionary)m_dict).Values; public void Add(TKey key, TValue value) { m_dict.Add(key, value); UpdateList(); } public void Clear() { m_dict.Clear(); UpdateList(); } public bool ContainsKey(TKey key) { return m_dict.ContainsKey(key); } public bool ContainsValue(TValue value) { return m_dict.ContainsValue(value); } public bool Remove(TKey key) { var result = m_dict.Remove(key); if (result) UpdateList(); return result; } public bool Remove(TKey key, out TValue value) { var result = m_dict.Remove(key, out value); if (result) UpdateList(); return result; } public int EnsureCapacity(int capacity) { return m_dict.EnsureCapacity(capacity); } public virtual bool Equals(object? obj) { return m_dict.Equals(obj); } public System.Collections.Generic.Dictionary.Enumerator GetEnumerator() { return m_dict.GetEnumerator(); } public virtual int GetHashCode() { return m_dict.GetHashCode(); } public Type GetType() { return m_dict.GetType(); } public virtual string? ToString() { return m_dict.ToString(); } public void TrimExcess() { m_dict.TrimExcess(); } public void TrimExcess(int capacity) { m_dict.TrimExcess(capacity); } public bool TryAdd(TKey key, TValue value) { var result = m_dict.TryAdd(key, value); if (result) UpdateList(); return result; } public bool TryGetValue(TKey key, out TValue value) { return m_dict.TryGetValue(key, out value); } public TValue this[TKey key] { get => ((IDictionary)m_dict)[key]; set => ((IDictionary)m_dict)[key] = value; } IEnumerator IEnumerable.GetEnumerator() { return ((IDictionary)m_dict).GetEnumerator(); } public void CopyTo(Array array, int index) { ((IDictionary)m_dict).CopyTo(array, index); } public bool IsSynchronized => ((IDictionary)m_dict).IsSynchronized; public object SyncRoot => ((IDictionary)m_dict).SyncRoot; public System.Collections.Generic.Dictionary.KeyCollection Keys => m_dict.Keys; public System.Collections.Generic.Dictionary.ValueCollection Values => m_dict.Values; } [Serializable] public class DictionaryCustomData { public TKey key; public TValue value; public DictionaryCustomData(TKey _key, TValue _value) { key = _key; value = _value; } } } ================================================ FILE: VirtueSky/DataType/DictionaryCustom.cs.meta ================================================ fileFormatVersion: 2 guid: f566d8a0c4f24f2d8406864e8db1571d timeCreated: 1721577270 ================================================ FILE: VirtueSky/DataType/ShortDouble.Units.cs ================================================ using System; namespace VirtueSky.DataType { public partial struct ShortDouble { static Unit FindUnit(double value) { return _unitFinder.Invoke(value); } public static class Unit0 { static readonly Unit[] Units; static readonly Unit Infinity; static readonly Unit Zero; static Unit0() { Infinity.exponent = 0; Infinity.name = "(VeryBIG)"; Zero.exponent = 0; Zero.name = ""; Units = new Unit[120]; var i = 0; Units[i++].name = ""; Units[i - 1].exponent = (i - 1) * 3; Units[i++].name = "k"; Units[i - 1].exponent = (i - 1) * 3; Units[i++].name = "m"; Units[i - 1].exponent = (i - 1) * 3; Units[i++].name = "b"; Units[i - 1].exponent = (i - 1) * 3; Units[i++].name = "t"; Units[i - 1].exponent = (i - 1) * 3; for (var c0 = 'a'; c0 <= 'z'; c0++) { for (var c1 = c0; c1 <= 'z'; c1++) { if (i >= Units.Length) { break; } Units[i++].name = c0.ToString() + c1.ToString(); Units[i - 1].exponent = (i - 1) * 3; } } } public static Unit Find(double value) { //extract var e = Math.Log10(Math.Abs(value)); var fe = Math.Floor(e); var exponent = Math.DivRem((long)fe, 3, out _) * 3; //find if (exponent < 0) return Zero; return exponent / 3 < Units.Length ? Units[exponent / 3] : Infinity; } } public static class Unit1 { static readonly Unit[] Units; static readonly Unit Infinity; static readonly Unit Zero; static Unit1() { Infinity.exponent = 0; Infinity.name = "(VeryBIG)"; Zero.exponent = 0; Zero.name = ""; Units = new Unit[304]; var i = 0; Units[i++].name = ""; Units[i - 1].exponent = (i - 1) * 3; Units[i++].name = "K"; Units[i - 1].exponent = (i - 1) * 3; Units[i++].name = "M"; Units[i - 1].exponent = (i - 1) * 3; Units[i++].name = "B"; Units[i - 1].exponent = (i - 1) * 3; Units[i++].name = "T"; Units[i - 1].exponent = (i - 1) * 3; var exp = 14; for (var j = i; j < Units.Length; j++) { Units[j].name = "e" + (++exp); Units[j].exponent = exp; } } public static Unit Find(double value) { //extract long exponent; var e = Math.Log10(Math.Abs(value)); var fe = Math.Floor(e); if (fe < 15) { exponent = Math.DivRem((long)fe, 3, out _) * 3; } else exponent = (long)fe; //find if (exponent < 0) return Zero; if (exponent < 15) return Units[exponent / 3]; return exponent < Units.Length + 5 ? Units[15 / 3 + exponent - 15] : Infinity; } } public static class Unit2 { private static readonly Unit[] Units; private static readonly Unit Infinity; private static readonly Unit Zero; private static readonly string[] Signs = { "", "k", "m", "b", "t", "q", "Q", "s", "S", "o", "n", "d", "u", "Du", "Tr", "Qu", "Qi", "Sx", "Sp", "Oc", "No", "Vi", "Ce" }; static Unit2() { Infinity.exponent = 0; Infinity.name = "(VeryBIG)"; Zero.exponent = 0; Zero.name = ""; Units = new Unit[Signs.Length]; for (var i = 0; i < Signs.Length; i++) { Units[i].name = Signs[i]; Units[i].exponent = i * 3; } } public static Unit Find(double value) { var e = Math.Log10(Math.Abs(value)); var fe = Math.Floor(e); var exponent = Math.DivRem((long)fe, 3, out long remainder) * 3; if (exponent < 0) return Zero; return exponent / 3 < Units.Length ? Units[exponent / 3] : Infinity; } } public struct Unit { public int exponent; public string name; } } } ================================================ FILE: VirtueSky/DataType/ShortDouble.Units.cs.meta ================================================ fileFormatVersion: 2 guid: 7c10ed2d72cf4d26ba8c0bdfe8ec3d7f timeCreated: 1617701321 ================================================ FILE: VirtueSky/DataType/ShortDouble.cs ================================================ using System; using System.Runtime.InteropServices; using Newtonsoft.Json; using UnityEditor; using UnityEngine; namespace VirtueSky.DataType { [Serializable, JsonObject(MemberSerialization.OptIn)] public partial struct ShortDouble : IFormattable, IComparable, IEquatable, IComparable { static Func _unitFinder; static ShortDouble() { _unitFinder = Unit0.Find; } [SerializeField] double value; public ShortDouble(double value = 0) { this.value = value; } public double Value => value; // Implicit convert double to SecuredDouble public static implicit operator ShortDouble(double value) => new ShortDouble(value); // Implicit convert SecuredDouble to double public static implicit operator double(ShortDouble value) => value.Value; public static ShortDouble operator +(ShortDouble a, ShortDouble b) => new ShortDouble(a.Value + b.Value); public static ShortDouble operator -(ShortDouble a, ShortDouble b) => new ShortDouble(a.Value - b.Value); public static ShortDouble operator *(ShortDouble a, ShortDouble b) => new ShortDouble(a.Value * b.Value); public static ShortDouble operator /(ShortDouble a, ShortDouble b) => new ShortDouble(a.Value / b.Value); public static bool operator >(ShortDouble a, ShortDouble b) => a.Value > b.Value; public static bool operator >=(ShortDouble a, ShortDouble b) => a.Value >= b.Value; public static bool operator <(ShortDouble a, ShortDouble b) => a.Value < b.Value; public static bool operator <=(ShortDouble a, ShortDouble b) => a.Value <= b.Value; public ShortDouble Floor => new ShortDouble(Math.Floor(Value)); public ShortDouble Ceiling => new ShortDouble(Math.Ceiling(Value)); public ShortDouble Round => new ShortDouble(Math.Round(Value)); public float AsFloat() => (float)Value; public long AsLong() => (long)Value; public bool AsBool(float eps = 0.3f) => Value > eps; public int AsInt() => (int)Value; public bool True => AsBool(); public ShortDouble Pow(double p) => new ShortDouble(Math.Pow(Value, p)); public static ShortDouble Max(ShortDouble a, ShortDouble b) => a > b ? a : b; public static ShortDouble Min(ShortDouble a, ShortDouble b) => a > b ? b : a; public static ShortDouble Clamp(ShortDouble value, ShortDouble min, ShortDouble max) => value < min ? min : (value > max ? max : value); public int CompareTo(ShortDouble other) => Value.CompareTo(other.Value); public int CompareTo(object obj) => Value.CompareTo(obj); public bool Equals(ShortDouble other) => Value.Equals(other.Value); public override bool Equals(object other) { if (other == null || GetType() != other.GetType()) return false; return Value.Equals(((ShortDouble)other).Value); } public override int GetHashCode() => Value.GetHashCode(); public override string ToString() => ToString(FindUnit(Value), "0.#"); public string ToString(string format) => ToString(FindUnit(Value), format); public string ToString(IFormatProvider provider) => Value.ToString(provider); public string ToString(string format, IFormatProvider provider) => ToString(FindUnit(Value), format, provider); string ToString(Unit unit, string format = "0.##") { if (double.IsInfinity(Value) || double.IsNaN(Value)) { return "Infinity or NaN"; } return (Value / System.Math.Pow(10, unit.exponent)).ToString(format) + unit.name; } string ToString(Unit unit, string format, IFormatProvider provider) { if (double.IsInfinity(Value) || double.IsNaN(Value)) { return "Infinity or NaN"; } return (Value / System.Math.Pow(10, unit.exponent)).ToString(format, provider) + unit.name; } public static void SetUnit(int u) { if (u == 0) { _unitFinder = Unit0.Find; } else if (u == 1) { _unitFinder = Unit1.Find; } else { _unitFinder = Unit2.Find; } } } #if UNITY_EDITOR [CustomPropertyDrawer(typeof(ShortDouble))] public class ShortDoubleDrawer : PropertyDrawer { public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { EditorGUI.BeginProperty(position, label, property); position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label); var indent = EditorGUI.indentLevel; EditorGUI.indentLevel = 0; EditorGUI.PropertyField(position, property.FindPropertyRelative("value"), GUIContent.none); EditorGUI.indentLevel = indent; EditorGUI.EndProperty(); } } #endif } ================================================ FILE: VirtueSky/DataType/ShortDouble.cs.meta ================================================ fileFormatVersion: 2 guid: 3a7fad66991554a129cbbd53d0878356 timeCreated: 1504925677 licenseType: Pro MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/DataType/virtuesky.sunflower.datatype.asmdef ================================================ { "name": "Virtuesky.Sunflower.DataType", "rootNamespace": "", "references": [ "GUID:fca7ec166e04dc948b624a983315e2c9", "GUID:324caed91501a9c47a04ebfd87b68794" ], "includePlatforms": [], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], "versionDefines": [], "noEngineReferences": false } ================================================ FILE: VirtueSky/DataType/virtuesky.sunflower.datatype.asmdef.meta ================================================ fileFormatVersion: 2 guid: 540154dd0c5ed9a4dbbe695c402232fb AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/DataType.meta ================================================ fileFormatVersion: 2 guid: e272376fd682f6b46a867b4eab4fc8cc folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Editor/BaseEventEditor.cs ================================================ using System.Reflection; using UnityEditor; using UnityEngine; namespace VirtueSky.Events { // [CustomEditor(typeof(BaseEvent), true)] // public class BaseEventNoParamEditor : Editor // { // private MethodInfo _methodInfo; // // void OnEnable() // { // _methodInfo = target.GetType().BaseType.GetMethod("DebugRaiseEvent", // BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); // } // // public override void OnInspectorGUI() // { // base.OnInspectorGUI(); // GUILayout.Space(10); // GUI.enabled = EditorApplication.isPlaying; // if (GUILayout.Button("Raise")) // { // _methodInfo.Invoke(target, null); // } // // GUI.enabled = true; // } // } // // [CustomEditor(typeof(BaseEvent<>), true)] // public class BaseEventParamEditor : UnityEditor.Editor // { // private MethodInfo _methodInfo; // // void OnEnable() // { // _methodInfo = target.GetType().BaseType.GetMethod("DebugRaiseEvent", // BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); // } // // public override void OnInspectorGUI() // { // base.OnInspectorGUI(); // GUILayout.Space(10); // GUI.enabled = EditorApplication.isPlaying; // if (GUILayout.Button("Raise")) // { // _methodInfo.Invoke(target, null); // } // // GUI.enabled = true; // } // } // // [CustomEditor(typeof(BaseEvent<,>), true)] // public class BaseEventResultEditor : UnityEditor.Editor // { // private MethodInfo _methodInfo; // private SerializedProperty _valueResult; // // void OnEnable() // { // _methodInfo = target.GetType().BaseType.GetMethod("DebugRaiseEvent", // BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); // } // // public override void OnInspectorGUI() // { // base.OnInspectorGUI(); // GUILayout.Space(10); // _valueResult = serializedObject.FindProperty("valueResult"); // GUI.enabled = EditorApplication.isPlaying; // // if (GUILayout.Button("Raise")) // { // _methodInfo.Invoke(target, null); // } // // EditorGUILayout.PropertyField(_valueResult); // GUI.enabled = true; // } // } } ================================================ FILE: VirtueSky/Events/Editor/BaseEventEditor.cs.meta ================================================ fileFormatVersion: 2 guid: fe06611ca91e4ac7afd485ec6444c37a timeCreated: 1708743122 ================================================ FILE: VirtueSky/Events/Editor/EventWindowEditor.cs ================================================ using UnityEditor; namespace VirtueSky.Events { #if UNITY_EDITOR using VirtueSky.UtilsEditor; public class EventWindowEditor : EditorWindow { #region Create ScriptableObject Event private const string pathEvent = "/Event"; private const string menuEvent = "Sunflower/Scriptable/Create Event/"; [MenuItem(menuEvent + "EventNoParam")] public static void CreateEventNoParam() { CreateAsset.CreateScriptableAssetsOnlyName(pathEvent, "so_event_no_param"); } [MenuItem(menuEvent + "String Event")] public static void CreateEventString() { CreateAsset.CreateScriptableAssetsOnlyName(pathEvent, "so_string_event"); } [MenuItem(menuEvent + "Float Event")] public static void CreateEventFloat() { CreateAsset.CreateScriptableAssetsOnlyName(pathEvent, "so_float_event"); } [MenuItem(menuEvent + "Integer Event")] public static void CreateEventInt() { CreateAsset.CreateScriptableAssetsOnlyName(pathEvent, "so_int_event"); } [MenuItem(menuEvent + "Boolean Event")] public static void CreateEventBoolean() { CreateAsset.CreateScriptableAssetsOnlyName(pathEvent, "so_bool_event"); } [MenuItem(menuEvent + "Object Event")] public static void CreateEventObject() { CreateAsset.CreateScriptableAssetsOnlyName(pathEvent, "so_object_event"); } [MenuItem(menuEvent + "Short Double Event")] public static void CreateEventShortDouble() { CreateAsset.CreateScriptableAssetsOnlyName(pathEvent, "so_short_double_event"); } [MenuItem(menuEvent + "Dictionary Event")] public static void CreateEventDictionary() { CreateAsset.CreateScriptableAssetsOnlyName(pathEvent, "so_dictionary_event"); } [MenuItem(menuEvent + "Vector3 Event")] public static void CreateEventVector3() { CreateAsset.CreateScriptableAssetsOnlyName(pathEvent, "so_vector3_event"); } [MenuItem(menuEvent + "Vector2 Event")] public static void CreateEventVector2() { CreateAsset.CreateScriptableAssetsOnlyName(pathEvent, "so_vector2_event"); } [MenuItem(menuEvent + "GameObject Event")] public static void CreateEventGameObject() { CreateAsset.CreateScriptableAssetsOnlyName(pathEvent, "so_gameobject_event"); } [MenuItem(menuEvent + "Transform Event")] public static void CreateEventTransform() { CreateAsset.CreateScriptableAssetsOnlyName(pathEvent, "so_transform_event"); } #endregion #region Create Scriptable Event Result private const string pathEventResult = "/Event_Result"; private const string menuEventResult = "Sunflower/Scriptable/Create Event-Result/"; #region Bool Event - Result private const string menuBoolEventResult = "Bool Event/"; private const string pathBoolEventResult = "/Bool_Event_Result"; [MenuItem(menuEventResult + menuBoolEventResult + "Bool Result")] public static void CreateBoolEventBoolResult() { CreateAsset.CreateScriptableAssetsOnlyName(pathEventResult + pathBoolEventResult, "bool_event_bool_result"); } [MenuItem(menuEventResult + menuBoolEventResult + "Float Result")] public static void CreateBoolEventFloatResult() { CreateAsset.CreateScriptableAssetsOnlyName(pathEventResult + pathBoolEventResult, "bool_event_float_result"); } [MenuItem(menuEventResult + menuBoolEventResult + "Int Result")] public static void CreateBoolEventIntResult() { CreateAsset.CreateScriptableAssetsOnlyName(pathEventResult + pathBoolEventResult, "bool_event_int_result"); } [MenuItem(menuEventResult + menuBoolEventResult + "Object Result")] public static void CreateBoolEventObjectResult() { CreateAsset.CreateScriptableAssetsOnlyName(pathEventResult + pathBoolEventResult, "bool_event_object_result"); } [MenuItem(menuEventResult + menuBoolEventResult + "String Result")] public static void CreateBoolEventStringResult() { CreateAsset.CreateScriptableAssetsOnlyName(pathEventResult + pathBoolEventResult, "bool_event_string_result"); } [MenuItem(menuEventResult + menuBoolEventResult + "Vector3 Result")] public static void CreateBoolEventVector3Result() { CreateAsset.CreateScriptableAssetsOnlyName(pathEventResult + pathBoolEventResult, "bool_event_vector3_result"); } [MenuItem(menuEventResult + menuBoolEventResult + "GameObject Result")] public static void CreateBoolEventGameObjectResult() { CreateAsset.CreateScriptableAssetsOnlyName(pathEventResult + pathBoolEventResult, "bool_event_gameobject_result"); } [MenuItem(menuEventResult + menuBoolEventResult + "Transform Result")] public static void CreateBoolEventTransformResult() { CreateAsset.CreateScriptableAssetsOnlyName(pathEventResult + pathBoolEventResult, "bool_event_transform_result"); } #endregion #region Float Event - Result private const string menuFloatEventResult = "Float Event/"; private const string pathFloatEventResult = "/Float_Event_Result"; [MenuItem(menuEventResult + menuFloatEventResult + "Bool Result")] public static void CreateFloatEventBoolResult() { CreateAsset.CreateScriptableAssetsOnlyName(pathEventResult + pathFloatEventResult, "float_event_bool_result"); } [MenuItem(menuEventResult + menuFloatEventResult + "Float Result")] public static void CreateFloatEventFloatResult() { CreateAsset.CreateScriptableAssetsOnlyName(pathEventResult + pathFloatEventResult, "float_event_float_result"); } [MenuItem(menuEventResult + menuFloatEventResult + "Int Result")] public static void CreateFloatEventIntResult() { CreateAsset.CreateScriptableAssetsOnlyName(pathEventResult + pathFloatEventResult, "float_event_int_result"); } [MenuItem(menuEventResult + menuFloatEventResult + "Object Result")] public static void CreateFloatEventObjectResult() { CreateAsset.CreateScriptableAssetsOnlyName(pathEventResult + pathFloatEventResult, "float_event_object_result"); } [MenuItem(menuEventResult + menuFloatEventResult + "String Result")] public static void CreateFloatEventStringResult() { CreateAsset.CreateScriptableAssetsOnlyName(pathEventResult + pathFloatEventResult, "float_event_string_result"); } [MenuItem(menuEventResult + menuFloatEventResult + "Vector3 Result")] public static void CreateFloatEventVector3Result() { CreateAsset.CreateScriptableAssetsOnlyName(pathEventResult + pathFloatEventResult, "float_event_vector3_result"); } [MenuItem(menuEventResult + menuFloatEventResult + "GameObject Result")] public static void CreateFloatEventGameObjectResult() { CreateAsset.CreateScriptableAssetsOnlyName( pathEventResult + pathFloatEventResult, "float_event_gameobject_result"); } [MenuItem(menuEventResult + menuFloatEventResult + "Transform Result")] public static void CreateFloatEventTransformResult() { CreateAsset.CreateScriptableAssetsOnlyName( pathEventResult + pathFloatEventResult, "float_event_transform_result"); } #endregion #region Int Event - Result private const string menuIntEventResult = "Int Event/"; private const string pathIntEventResult = "/Int_Event_Result"; [MenuItem(menuEventResult + menuIntEventResult + "Bool Result")] public static void CreateIntEventBoolResult() { CreateAsset.CreateScriptableAssetsOnlyName(pathEventResult + pathIntEventResult, "int_event_bool_result"); } [MenuItem(menuEventResult + menuIntEventResult + "Float Result")] public static void CreateIntEventFloatResult() { CreateAsset.CreateScriptableAssetsOnlyName(pathEventResult + pathIntEventResult, "int_event_float_result"); } [MenuItem(menuEventResult + menuIntEventResult + "Int Result")] public static void CreateIntEventIntResult() { CreateAsset.CreateScriptableAssetsOnlyName(pathEventResult + pathIntEventResult, "int_event_int_result"); } [MenuItem(menuEventResult + menuIntEventResult + "Object Result")] public static void CreateIntEventObjectResult() { CreateAsset.CreateScriptableAssetsOnlyName(pathEventResult + pathIntEventResult, "int_event_object_result"); } [MenuItem(menuEventResult + menuIntEventResult + "String Result")] public static void CreateIntEventStringResult() { CreateAsset.CreateScriptableAssetsOnlyName(pathEventResult + pathIntEventResult, "int_event_string_result"); } [MenuItem(menuEventResult + menuIntEventResult + "Vector3 Result")] public static void CreateIntEventVector3Result() { CreateAsset.CreateScriptableAssetsOnlyName(pathEventResult + pathIntEventResult, "int_event_vector3_result"); } [MenuItem(menuEventResult + menuIntEventResult + "GameObject Result")] public static void CreateIntEventGameObjectResult() { CreateAsset.CreateScriptableAssetsOnlyName(pathEventResult + pathIntEventResult, "int_event_gameobject_result"); } [MenuItem(menuEventResult + menuIntEventResult + "Transform Result")] public static void CreateIntEventTransformResult() { CreateAsset.CreateScriptableAssetsOnlyName(pathEventResult + pathIntEventResult, "int_event_transform_result"); } #endregion #region Object Event - Result private const string menuObjectEventResult = "Object Event/"; private const string pathObjectEventResult = "/Object_Event_Result"; [MenuItem(menuEventResult + menuObjectEventResult + "Bool Result")] public static void CreateObjectEventBoolResult() { CreateAsset.CreateScriptableAssetsOnlyName(pathEventResult + pathObjectEventResult, "object_event_bool_result"); } [MenuItem(menuEventResult + menuObjectEventResult + "Float Result")] public static void CreateObjectEventFloatResult() { CreateAsset.CreateScriptableAssetsOnlyName(pathEventResult + pathObjectEventResult, "object_event_float_result"); } [MenuItem(menuEventResult + menuObjectEventResult + "Int Result")] public static void CreateObjectEventIntResult() { CreateAsset.CreateScriptableAssetsOnlyName(pathEventResult + pathObjectEventResult, "object_event_int_result"); } [MenuItem(menuEventResult + menuObjectEventResult + "Object Result")] public static void CreateObjectEventObjectResult() { CreateAsset.CreateScriptableAssetsOnlyName(pathEventResult + pathObjectEventResult, "object_event_object_result"); } [MenuItem(menuEventResult + menuObjectEventResult + "String Result")] public static void CreateObjectEventStringResult() { CreateAsset.CreateScriptableAssetsOnlyName(pathEventResult + pathObjectEventResult, "object_event_string_result"); } [MenuItem(menuEventResult + menuObjectEventResult + "Vector3 Result")] public static void CreateObjectEventVector3Result() { CreateAsset.CreateScriptableAssetsOnlyName( pathEventResult + pathObjectEventResult, "object_event_vector3_result"); } [MenuItem(menuEventResult + menuObjectEventResult + "GameObject Result")] public static void CreateObjectEventGameObjectResult() { CreateAsset.CreateScriptableAssetsOnlyName( pathEventResult + pathObjectEventResult, "object_event_gameobject_result"); } [MenuItem(menuEventResult + menuObjectEventResult + "Transform Result")] public static void CreateObjectEventTransformResult() { CreateAsset.CreateScriptableAssetsOnlyName( pathEventResult + pathObjectEventResult, "object_event_transform_result"); } #endregion #region String Event - Result private const string menuStringEventResult = "String Event/"; private const string pathStringEventResult = "/String_Event_Result"; [MenuItem(menuEventResult + menuStringEventResult + "Bool Result")] public static void CreateStringEventBoolResult() { CreateAsset.CreateScriptableAssetsOnlyName(pathEventResult + pathStringEventResult, "string_event_bool_result"); } [MenuItem(menuEventResult + menuStringEventResult + "Float Result")] public static void CreateStringEventFloatResult() { CreateAsset.CreateScriptableAssetsOnlyName(pathEventResult + pathStringEventResult, "string_event_float_result"); } [MenuItem(menuEventResult + menuStringEventResult + "Int Result")] public static void CreateStringEventIntResult() { CreateAsset.CreateScriptableAssetsOnlyName(pathEventResult + pathStringEventResult, "string_event_int_result"); } [MenuItem(menuEventResult + menuStringEventResult + "Object Result")] public static void CreateStringEventObjectResult() { CreateAsset.CreateScriptableAssetsOnlyName(pathEventResult + pathStringEventResult, "string_event_object_result"); } [MenuItem(menuEventResult + menuStringEventResult + "String Result")] public static void CreateStringEventStringResult() { CreateAsset.CreateScriptableAssetsOnlyName(pathEventResult + pathStringEventResult, "string_event_string_result"); } [MenuItem(menuEventResult + menuStringEventResult + "Vector3 Result")] public static void CreateStringEventVector3Result() { CreateAsset.CreateScriptableAssetsOnlyName( pathEventResult + pathStringEventResult, "string_event_vector3_result"); } [MenuItem(menuEventResult + menuStringEventResult + "GameObject Result")] public static void CreateStringEventGameObjectResult() { CreateAsset.CreateScriptableAssetsOnlyName( pathEventResult + pathStringEventResult, "string_event_gameobject_result"); } [MenuItem(menuEventResult + menuStringEventResult + "Transform Result")] public static void CreateStringEventTransformResult() { CreateAsset.CreateScriptableAssetsOnlyName( pathEventResult + pathStringEventResult, "string_event_transform_result"); } #endregion #region Vector3 Event - Result private const string menuVector3EventResult = "Vector3 Event/"; private const string pathVector3EventResult = "/Vector3_Event_Result"; [MenuItem(menuEventResult + menuVector3EventResult + "Bool Result")] public static void CreateVector3EventBoolResult() { CreateAsset.CreateScriptableAssetsOnlyName(pathEventResult + pathVector3EventResult, "vector3_event_bool_result"); } [MenuItem(menuEventResult + menuVector3EventResult + "Float Result")] public static void CreateVector3EventFloatResult() { CreateAsset.CreateScriptableAssetsOnlyName( pathEventResult + pathVector3EventResult, "vector3_event_float_result"); } [MenuItem(menuEventResult + menuVector3EventResult + "Int Result")] public static void CreateVector3EventIntResult() { CreateAsset.CreateScriptableAssetsOnlyName(pathEventResult + pathVector3EventResult, "vector3_event_int_result"); } [MenuItem(menuEventResult + menuVector3EventResult + "Object Result")] public static void CreateVector3EventObjectResult() { CreateAsset.CreateScriptableAssetsOnlyName( pathEventResult + pathVector3EventResult, "vector3_event_object_result"); } [MenuItem(menuEventResult + menuVector3EventResult + "String Result")] public static void CreateVector3EventStringResult() { CreateAsset.CreateScriptableAssetsOnlyName( pathEventResult + pathVector3EventResult, "vector3_event_string_result"); } [MenuItem(menuEventResult + menuVector3EventResult + "Vector3 Result")] public static void CreateVector3EventVector3Result() { CreateAsset.CreateScriptableAssetsOnlyName( pathEventResult + pathVector3EventResult, "vector3_event_vector3_result"); } [MenuItem(menuEventResult + menuVector3EventResult + "GameObject Result")] public static void CreateVector3EventGameObjectResult() { CreateAsset.CreateScriptableAssetsOnlyName( pathEventResult + pathVector3EventResult, "vector3_event_gameobject_result"); } [MenuItem(menuEventResult + menuVector3EventResult + "Transform Result")] public static void CreateVector3EventTransformResult() { CreateAsset.CreateScriptableAssetsOnlyName( pathEventResult + pathVector3EventResult, "vector3_event_transform_result"); } #endregion #region Event No Param - Result private const string menuEventNoParamResult = "Event No Param/"; private const string pathEventNoParamResult = "/Event_No_Param_Result"; [MenuItem(menuEventResult + menuEventNoParamResult + "Bool Result")] public static void CreateEventNoParamBoolResult() { CreateAsset.CreateScriptableAssetsOnlyName(pathEventResult + pathEventNoParamResult, "event_no_param_bool_result"); } [MenuItem(menuEventResult + menuEventNoParamResult + "Float Result")] public static void CreateEventNoParamFloatResult() { CreateAsset.CreateScriptableAssetsOnlyName( pathEventResult + pathEventNoParamResult, "event_no_param_float_result"); } [MenuItem(menuEventResult + menuEventNoParamResult + "Int Result")] public static void CreateEventNoParamIntResult() { CreateAsset.CreateScriptableAssetsOnlyName(pathEventResult + pathEventNoParamResult, "event_no_param_int_result"); } [MenuItem(menuEventResult + menuEventNoParamResult + "Object Result")] public static void CreateEventNoParamObjectResult() { CreateAsset.CreateScriptableAssetsOnlyName( pathEventResult + pathEventNoParamResult, "event_no_param_object_result"); } [MenuItem(menuEventResult + menuEventNoParamResult + "String Result")] public static void CreateEventNoParamStringResult() { CreateAsset.CreateScriptableAssetsOnlyName( pathEventResult + pathEventNoParamResult, "event_no_param_string_result"); } [MenuItem(menuEventResult + menuEventNoParamResult + "Vector3 Result")] public static void CreateEventNoParamVector3Result() { CreateAsset.CreateScriptableAssetsOnlyName( pathEventResult + pathEventNoParamResult, "event_no_param_vector3_result"); } [MenuItem(menuEventResult + menuEventNoParamResult + "GameObject Result")] public static void CreateEventNoParamGameObjectResult() { CreateAsset.CreateScriptableAssetsOnlyName( pathEventResult + pathEventNoParamResult, "event_no_param_gameobject_result"); } [MenuItem(menuEventResult + menuEventNoParamResult + "Transform Result")] public static void CreateEventNoParamTransformResult() { CreateAsset.CreateScriptableAssetsOnlyName( pathEventResult + pathEventNoParamResult, "event_no_param_transform_result"); } #endregion #region GameObject Event - Result private const string menuGameObjectEventResult = "GameObject Event/"; private const string pathGameObjectEventResult = "/GameObject_Event_Result"; [MenuItem(menuEventResult + menuGameObjectEventResult + "Bool Result")] public static void CreateGameObjectEventBoolResult() { CreateAsset.CreateScriptableAssetsOnlyName( pathEventResult + pathGameObjectEventResult, "gameobject_event_bool_result"); } [MenuItem(menuEventResult + menuGameObjectEventResult + "Float Result")] public static void CreateGameObjectEventFloatResult() { CreateAsset.CreateScriptableAssetsOnlyName( pathEventResult + pathGameObjectEventResult, "gameobject_event_float_result"); } [MenuItem(menuEventResult + menuGameObjectEventResult + "GameObject Result")] public static void CreateGameObjectEventGameObjectResult() { CreateAsset.CreateScriptableAssetsOnlyName( pathEventResult + pathGameObjectEventResult, "gameobject_event_gameobject_result"); } [MenuItem(menuEventResult + menuGameObjectEventResult + "Int Result")] public static void CreateGameObjectEventIntResult() { CreateAsset.CreateScriptableAssetsOnlyName( pathEventResult + pathGameObjectEventResult, "gameobject_event_int_result"); } [MenuItem(menuEventResult + menuGameObjectEventResult + "Object Result")] public static void CreateGameObjectEventObjectResult() { CreateAsset.CreateScriptableAssetsOnlyName( pathEventResult + pathGameObjectEventResult, "gameobject_event_object_result"); } [MenuItem(menuEventResult + menuGameObjectEventResult + "String Result")] public static void CreateGameObjectEventStringResult() { CreateAsset.CreateScriptableAssetsOnlyName( pathEventResult + pathGameObjectEventResult, "gameobject_event_string_result"); } [MenuItem(menuEventResult + menuGameObjectEventResult + "Transform Result")] public static void CreateGameObjectEventTransformResult() { CreateAsset.CreateScriptableAssetsOnlyName( pathEventResult + pathGameObjectEventResult, "gameobject_event_transform_result"); } [MenuItem(menuEventResult + menuGameObjectEventResult + "Vector3 Result")] public static void CreateGameObjectEventVector3Result() { CreateAsset.CreateScriptableAssetsOnlyName( pathEventResult + pathGameObjectEventResult, "gameobject_event_vector3_result"); } #endregion #region Transform Event - Result private const string menuTransformEventResult = "Transform Event/"; private const string pathTransformEventResult = "/Transform_Event_Result"; [MenuItem(menuEventResult + menuTransformEventResult + "Bool Result")] public static void CreateTransformEventBoolResult() { CreateAsset.CreateScriptableAssetsOnlyName( pathEventResult + pathTransformEventResult, "transform_event_bool_result"); } [MenuItem(menuEventResult + menuTransformEventResult + "Float Result")] public static void CreateTransformEventFloatResult() { CreateAsset.CreateScriptableAssetsOnlyName( pathEventResult + pathTransformEventResult, "transform_event_float_result"); } [MenuItem(menuEventResult + menuTransformEventResult + "GameObject Result")] public static void CreateTransformEventGameObjectResult() { CreateAsset.CreateScriptableAssetsOnlyName( pathEventResult + pathTransformEventResult, "transform_event_gameobject_result"); } [MenuItem(menuEventResult + menuTransformEventResult + "Int Result")] public static void CreateTransformEventIntResult() { CreateAsset.CreateScriptableAssetsOnlyName( pathEventResult + pathTransformEventResult, "transform_event_int_result"); } [MenuItem(menuEventResult + menuTransformEventResult + "Object Result")] public static void CreateTransformEventObjectResult() { CreateAsset.CreateScriptableAssetsOnlyName( pathEventResult + pathTransformEventResult, "transform_event_object_result"); } [MenuItem(menuEventResult + menuTransformEventResult + "String Result")] public static void CreateTransformEventStringResult() { CreateAsset.CreateScriptableAssetsOnlyName( pathEventResult + pathTransformEventResult, "transform_event_string_result"); } [MenuItem(menuEventResult + menuTransformEventResult + "Transform Result")] public static void CreateTransformEventTransformResult() { CreateAsset.CreateScriptableAssetsOnlyName( pathEventResult + pathTransformEventResult, "transform_event_transform_result"); } [MenuItem(menuEventResult + menuTransformEventResult + "Vector3 Result")] public static void CreateTransformEventVector3Result() { CreateAsset.CreateScriptableAssetsOnlyName( pathEventResult + pathTransformEventResult, "transform_event_vector3_result"); } #endregion #endregion } #endif } ================================================ FILE: VirtueSky/Events/Editor/EventWindowEditor.cs.meta ================================================ fileFormatVersion: 2 guid: d525cea821836b74681c2fd7108104c8 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Editor/virtuesky.sunflower.event.editor.asmdef ================================================ { "name": "virtuesky.sunflower.event.editor", "rootNamespace": "", "references": [ "GUID:bd40169efe8642149b1d2b72ba4903ce", "GUID:acb3cac55c622ec459c8caadf707623a", "GUID:c904f6d969e991d459a0843b71c22ec5" ], "includePlatforms": [ "Editor" ], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], "versionDefines": [], "noEngineReferences": false } ================================================ FILE: VirtueSky/Events/Editor/virtuesky.sunflower.event.editor.asmdef.meta ================================================ fileFormatVersion: 2 guid: ae37c1f040fc3574a93bca20d91449d9 AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Editor.meta ================================================ fileFormatVersion: 2 guid: 8c990f2aee3aee740b7cfb15c0f47dba folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Base_Event/BaseEvent.cs ================================================ using System; using System.Collections.Generic; using UnityEditor; using UnityEngine; using VirtueSky.Core; using VirtueSky.Inspector; namespace VirtueSky.Events { public class BaseEvent : BaseSO, IEvent { readonly List listeners = new List(); private Action onRaised = null; #if UNITY_EDITOR [ShowIf(nameof(ConditionShow))] [GUIColor(0.6f, 0.9f, 1.0f), Button("Raise")] private void DebugRaiseEvent() { Raise(); } protected bool ConditionShow => EditorApplication.isPlaying; #endif public void Raise() { #if UNITY_EDITOR // Debug.Log($"===> {name}"); #endif for (var i = listeners.Count - 1; i >= 0; i--) { listeners[i].OnEventRaised(this); } onRaised?.Invoke(); } public event Action OnRaised { add => onRaised += value; remove => onRaised -= value; } public void AddListener(Action action) { onRaised += action; } public void RemoveListener(Action action) { onRaised -= action; } public void AddListener(IEventListener listener) { if (!listeners.Contains(listener)) { listeners.Add(listener); } } public void RemoveListener(IEventListener listener) { if (listeners.Contains(listener)) { listeners.Remove(listener); } } public void RemoveAll() { listeners.Clear(); onRaised = null; } } public class BaseEvent : BaseSO, IEvent { readonly List> listeners = new List>(); private Action onRaised = null; #if UNITY_EDITOR [Space(10)] [ShowIf(nameof(ConditionShow))] [GUIColor(0.6f, 0.9f, 1.0f), SerializeField] private TType valueDebug = default(TType); [ShowIf(nameof(ConditionShow))] [GUIColor(0.6f, 0.9f, 1.0f), Button("Raise")] private void DebugRaiseEvent() { Raise(valueDebug); } protected bool ConditionShow => EditorApplication.isPlaying; #endif public virtual void Raise(TType value) { #if UNITY_EDITOR //Debug.Log($"===> {name}"); #endif for (var i = listeners.Count - 1; i >= 0; i--) { listeners[i].OnEventRaised(this, value); } onRaised?.Invoke(value); } public event Action OnRaised { add => onRaised += value; remove => onRaised -= value; } public void AddListener(Action action) { onRaised += action; } public void RemoveListener(Action action) { onRaised -= action; } public void AddListener(IEventListener listener) { if (!listeners.Contains(listener)) { listeners.Add(listener); } } public void RemoveListener(IEventListener listener) { if (listeners.Contains(listener)) { listeners.Remove(listener); } } public void RemoveAll() { listeners.Clear(); onRaised = null; } } public class BaseEvent : BaseSO, IEvent { readonly List> listeners = new List>(); private Func onRaised = null; #if UNITY_EDITOR [Space(10)] [ShowIf(nameof(ConditionShow))] [GUIColor(0.6f, 0.9f, 1.0f), SerializeField] private TType valueDebug = default(TType); [ShowIf(nameof(ConditionShow))] [GUIColor(0.6f, 0.9f, 1.0f), ReadOnly, SerializeField] private TResult valueResult = default(TResult); [ShowIf(nameof(ConditionShow))] [GUIColor(0.6f, 0.9f, 1.0f), Button("Raise")] private void DebugRaiseEvent() { valueResult = Raise(valueDebug); } protected bool ConditionShow => EditorApplication.isPlaying; #endif public TResult Raise(TType value) { TResult result = default; if (!Application.isPlaying) return result; for (var i = listeners.Count - 1; i >= 0; i--) { listeners[i].OnEventRaised(this, value); } if (onRaised != null) result = onRaised.Invoke(value); return result; } public event Func OnRaised { add { onRaised += value; } remove { onRaised -= value; } } public void AddListener(Func func) { onRaised += func; } public void RemoveListener(Func func) { onRaised -= func; } public void AddListener(IEventListener listener) { if (!listeners.Contains(listener)) { listeners.Add(listener); } } public void RemoveListener(IEventListener listener) { if (listeners.Contains(listener)) { listeners.Remove(listener); } } public void RemoveAll() { listeners.Clear(); onRaised = null; } } #if UNITY_EDITOR #endif } ================================================ FILE: VirtueSky/Events/Runtime/Base_Event/BaseEvent.cs.meta ================================================ fileFormatVersion: 2 guid: 7f885e714ddc92849ac280af904bba4f MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Base_Event/BaseEventListener.cs ================================================ using System; using System.Collections.Generic; using UnityEditor; using UnityEngine; using UnityEngine.Events; using VirtueSky.Core; using VirtueSky.Inspector; namespace VirtueSky.Events { public class BaseEventListener : EventListenerMono, IEventListener where TEvent : BaseEvent where TResponse : UnityEvent { [SerializeField] private EventResponseData[] listEventResponseDatas; private readonly Dictionary _dictionary = new Dictionary(); [Serializable] public class EventResponseData { public TEvent @event; public TResponse response; #if UNITY_EDITOR [ShowIf(nameof(ConditionShow))] [Button("Raise")] void DebugRaise() { @event.Raise(); } private bool ConditionShow => EditorApplication.isPlaying; #endif } protected override void ToggleListenerEvent(bool isListenerEvent) { if (isListenerEvent) { foreach (var t in listEventResponseDatas) { t.@event.AddListener(this); _dictionary.TryAdd(t.@event, t.response); } } else { foreach (var t in listEventResponseDatas) { t.@event.RemoveListener(this); if (_dictionary.ContainsKey(t.@event)) _dictionary.Remove(t.@event); } } } public virtual void OnEventRaised(BaseEvent eventRaise) { _dictionary[eventRaise]?.Invoke(); } } public class BaseEventListener : EventListenerMono, IEventListener where TEvent : BaseEvent where TResponse : UnityEvent { [SerializeField] protected EventResponseData[] listEventResponseDatas; protected readonly Dictionary, UnityEvent> _dictionary = new Dictionary, UnityEvent>(); [Serializable] public class EventResponseData { public TEvent @event; public TResponse response; #if UNITY_EDITOR [ShowIf(nameof(ConditionShow))] [SerializeField] private TType valueDebug; [ShowIf(nameof(ConditionShow))] [Button("Raise")] void DebugRaise() { @event.Raise(valueDebug); } private bool ConditionShow => EditorApplication.isPlaying; #endif } protected override void ToggleListenerEvent(bool isListenerEvent) { if (isListenerEvent) { foreach (var t in listEventResponseDatas) { t.@event.AddListener(this); _dictionary.TryAdd(t.@event, t.response); } } else { foreach (var t in listEventResponseDatas) { t.@event.RemoveListener(this); if (_dictionary.ContainsKey(t.@event)) _dictionary.Remove(t.@event); } } } public virtual void OnEventRaised(BaseEvent eventRaise, TType value) { _dictionary[eventRaise]?.Invoke(value); } } public class BaseEventListener : EventListenerMono, IEventListener where TEvent : BaseEvent where TResponse : UnityEvent { [SerializeField] protected EventResponseData[] listEventResponseDatas; protected readonly Dictionary, UnityEvent> _dictionary = new Dictionary, UnityEvent>(); [Serializable] public class EventResponseData { public TEvent @event; public TResponse response; } public void OnEventRaised(BaseEvent eventRaise, TType value) { _dictionary[eventRaise]?.Invoke(value); } protected override void ToggleListenerEvent(bool isListenerEvent) { if (isListenerEvent) { foreach (var t in listEventResponseDatas) { t.@event.AddListener(this); _dictionary.TryAdd(t.@event, t.response); } } else { foreach (var t in listEventResponseDatas) { t.@event.RemoveListener(this); if (_dictionary.ContainsKey(t.@event)) _dictionary.Remove(t.@event); } } } } } ================================================ FILE: VirtueSky/Events/Runtime/Base_Event/BaseEventListener.cs.meta ================================================ fileFormatVersion: 2 guid: 1f85358eae4b4fedbec94383e714f35c timeCreated: 1651562443 ================================================ FILE: VirtueSky/Events/Runtime/Base_Event/BaseEventResponse.cs ================================================ using UnityEngine.Events; namespace VirtueSky.Events { public class BaseEventResponse : UnityEvent, IEventResponse { } public class BaseEventResponse : UnityEvent, IEventResponse { } } ================================================ FILE: VirtueSky/Events/Runtime/Base_Event/BaseEventResponse.cs.meta ================================================ fileFormatVersion: 2 guid: 893521d098d1429489b6dc83598b1b1b timeCreated: 1651574321 ================================================ FILE: VirtueSky/Events/Runtime/Base_Event/EventListenerMono.cs ================================================ using System; using System.Collections.Generic; using UnityEngine; namespace VirtueSky.Events { public abstract class EventListenerMono : MonoBehaviour { [SerializeField] private BindingListener bindingListener; protected abstract void ToggleListenerEvent(bool isListenerEvent); private void Awake() { if (bindingListener == BindingListener.UNTIL_DESTROY) { ToggleListenerEvent(true); } } private void OnEnable() { if (bindingListener == BindingListener.UNTIL_DISABLE) { ToggleListenerEvent(true); } } private void OnDisable() { if (bindingListener == BindingListener.UNTIL_DISABLE) { ToggleListenerEvent(false); } } private void OnDestroy() { if (bindingListener == BindingListener.UNTIL_DESTROY) { ToggleListenerEvent(false); } } } public enum BindingListener { UNTIL_DISABLE, UNTIL_DESTROY } } ================================================ FILE: VirtueSky/Events/Runtime/Base_Event/EventListenerMono.cs.meta ================================================ fileFormatVersion: 2 guid: ffc0d5f5a5ab4ba7a4702668f69ba09d timeCreated: 1697612265 ================================================ FILE: VirtueSky/Events/Runtime/Base_Event.meta ================================================ fileFormatVersion: 2 guid: 892c2cea0ad241878ecb12183ab37cb7 timeCreated: 1697617884 ================================================ FILE: VirtueSky/Events/Runtime/Boolean_Event/BooleanEvent.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event/Boolean Event", fileName = "bool_event")] [EditorIcon("scriptable_event")] public class BooleanEvent : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Boolean_Event/BooleanEvent.cs.meta ================================================ fileFormatVersion: 2 guid: aef918ec277845979450b0fbea88e78b MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Boolean_Event/BooleanEventListener.cs ================================================ using VirtueSky.Inspector; namespace VirtueSky.Events { [EditorIcon("scriptable_event_listener")] public class BooleanEventListener : BaseEventListener { } } ================================================ FILE: VirtueSky/Events/Runtime/Boolean_Event/BooleanEventListener.cs.meta ================================================ fileFormatVersion: 2 guid: fd08215cd3194a57bd070df5454b8d18 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 23cedf6c21faf0b4eb783f1fb5d4679a, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Boolean_Event/BooleanEventResponse.cs ================================================ using System; namespace VirtueSky.Events { [Serializable] public class BooleanEventResponse : BaseEventResponse { } } ================================================ FILE: VirtueSky/Events/Runtime/Boolean_Event/BooleanEventResponse.cs.meta ================================================ fileFormatVersion: 2 guid: f5c01c8b67014dfb83f095ecacbb35f4 timeCreated: 1659151605 ================================================ FILE: VirtueSky/Events/Runtime/Boolean_Event/Event_Result/BoolEventBoolResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Boolean Event/Boolean Result", fileName = "bool_event_bool_result")] [EditorIcon("scriptable_event")] public class BoolEventBoolResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Boolean_Event/Event_Result/BoolEventBoolResult.cs.meta ================================================ fileFormatVersion: 2 guid: 7945a7b8329c496fa66fd66951b195ef MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Boolean_Event/Event_Result/BoolEventFloatResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Boolean Event/Float Result", fileName = "bool_event_float_result")] [EditorIcon("scriptable_event")] public class BoolEventFloatResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Boolean_Event/Event_Result/BoolEventFloatResult.cs.meta ================================================ fileFormatVersion: 2 guid: 76ea5d4b4cc8493ebcef45f72a23608c MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Boolean_Event/Event_Result/BoolEventGameObjectResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Boolean Event/GameObject Result", fileName = "bool_event_gameobject_result")] [EditorIcon("scriptable_event")] public class BoolEventGameObjectResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Boolean_Event/Event_Result/BoolEventGameObjectResult.cs.meta ================================================ fileFormatVersion: 2 guid: bfd630b8a8424ff781cf4af941463720 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Boolean_Event/Event_Result/BoolEventIntResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Boolean Event/Int Result", fileName = "bool_event_int_result")] [EditorIcon("scriptable_event")] public class BoolEventIntResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Boolean_Event/Event_Result/BoolEventIntResult.cs.meta ================================================ fileFormatVersion: 2 guid: d23d33af0f7a4ca78fdbc1f5f0c51e04 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Boolean_Event/Event_Result/BoolEventObjectResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Boolean Event/Object Result", fileName = "bool_event_object_result")] [EditorIcon("scriptable_event")] public class BoolEventObjectResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Boolean_Event/Event_Result/BoolEventObjectResult.cs.meta ================================================ fileFormatVersion: 2 guid: be2e3ed588b74c61b261e24ebe469019 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Boolean_Event/Event_Result/BoolEventStringResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Boolean Event/String Result", fileName = "bool_event_string_result")] [EditorIcon("scriptable_event")] public class BoolEventStringResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Boolean_Event/Event_Result/BoolEventStringResult.cs.meta ================================================ fileFormatVersion: 2 guid: 6d3f4e07c1f843b28cba61dad278994d MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Boolean_Event/Event_Result/BoolEventTransformResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Boolean Event/Transform Result", fileName = "bool_event_transform_result")] [EditorIcon("scriptable_event")] public class BoolEventTransformResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Boolean_Event/Event_Result/BoolEventTransformResult.cs.meta ================================================ fileFormatVersion: 2 guid: 3827e644d1414c22818adb6ad27237ab MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Boolean_Event/Event_Result/BoolEventVector3Result.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Boolean Event/Vector3 Result", fileName = "bool_event_vector3_result")] [EditorIcon("scriptable_event")] public class BoolEventVector3Result : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Boolean_Event/Event_Result/BoolEventVector3Result.cs.meta ================================================ fileFormatVersion: 2 guid: ec64add237eb452a90562dadaf8d8cbf MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Boolean_Event/Event_Result.meta ================================================ fileFormatVersion: 2 guid: 14a616b32e884ca78656c271efb32461 timeCreated: 1708746295 ================================================ FILE: VirtueSky/Events/Runtime/Boolean_Event.meta ================================================ fileFormatVersion: 2 guid: 6b45161106b8fd241b098ad985d4938e folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Custom/ClickButtonEvent.cs ================================================ using VirtueSky.Inspector; namespace VirtueSky.Events { [EditorIcon("scriptable_event")] public class ClickButtonEvent : EventNoParam { } } ================================================ FILE: VirtueSky/Events/Runtime/Custom/ClickButtonEvent.cs.meta ================================================ fileFormatVersion: 2 guid: 34f5aa4023cc40ee952b894df1be543c MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Custom.meta ================================================ fileFormatVersion: 2 guid: c58a6109373d49e3b55b1d33844e1ee6 timeCreated: 1720080443 ================================================ FILE: VirtueSky/Events/Runtime/Dictionary_Event/DictionaryEvent.cs ================================================ using System.Collections.Generic; using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event/DictionaryEvent", fileName = "dictionary_event")] [EditorIcon("scriptable_event")] public class DictionaryEvent : BaseEvent> { } } ================================================ FILE: VirtueSky/Events/Runtime/Dictionary_Event/DictionaryEvent.cs.meta ================================================ fileFormatVersion: 2 guid: 814787ad80ba44cea17a4a3b6d536ef1 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Dictionary_Event/DictionaryEventListener.cs ================================================ using System.Collections.Generic; using VirtueSky.Inspector; namespace VirtueSky.Events { [EditorIcon("scriptable_event_listener")] public class DictionaryEventListener : BaseEventListener, DictionaryEvent, DictionaryEventResponse> { } } ================================================ FILE: VirtueSky/Events/Runtime/Dictionary_Event/DictionaryEventListener.cs.meta ================================================ fileFormatVersion: 2 guid: 566e31263e25463eb7afbf70fdc47acc MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 23cedf6c21faf0b4eb783f1fb5d4679a, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Dictionary_Event/DictionaryEventResponse.cs ================================================ using System; using System.Collections.Generic; namespace VirtueSky.Events { [Serializable] public class DictionaryEventResponse : BaseEventResponse> { } } ================================================ FILE: VirtueSky/Events/Runtime/Dictionary_Event/DictionaryEventResponse.cs.meta ================================================ fileFormatVersion: 2 guid: 55e065f206f040459d9ddb559fd3ad40 timeCreated: 1659155254 ================================================ FILE: VirtueSky/Events/Runtime/Dictionary_Event.meta ================================================ fileFormatVersion: 2 guid: 341bcf9b0a48d1d4583485ea7d08fc3c folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Event_NoParam/EventListenerNoParam.cs ================================================ using VirtueSky.Inspector; namespace VirtueSky.Events { [EditorIcon("scriptable_event_listener")] public class EventListenerNoParam : BaseEventListener { } } ================================================ FILE: VirtueSky/Events/Runtime/Event_NoParam/EventListenerNoParam.cs.meta ================================================ fileFormatVersion: 2 guid: f477bc0650f64520ad655afc7aacef99 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 23cedf6c21faf0b4eb783f1fb5d4679a, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Event_NoParam/EventNoParam.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event/Event No Param", fileName = "event_no_param")] [EditorIcon("scriptable_event")] public class EventNoParam : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Event_NoParam/EventNoParam.cs.meta ================================================ fileFormatVersion: 2 guid: 719558c56beb4a8d98cf058fadf5455a MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Event_NoParam/EventResponse.cs ================================================ using System; namespace VirtueSky.Events { [Serializable] public class EventResponse : BaseEventResponse { } } ================================================ FILE: VirtueSky/Events/Runtime/Event_NoParam/EventResponse.cs.meta ================================================ fileFormatVersion: 2 guid: dbe3c2bf266f40799ca5f846bd5b42e9 timeCreated: 1651572748 ================================================ FILE: VirtueSky/Events/Runtime/Event_NoParam/Event_Result/EventNoParamBoolResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Event No Param/Boolean Result", fileName = "event_no_param_bool_result")] [EditorIcon("scriptable_event")] public class EventNoParamBoolResult : EventNoParamResult { } } ================================================ FILE: VirtueSky/Events/Runtime/Event_NoParam/Event_Result/EventNoParamBoolResult.cs.meta ================================================ fileFormatVersion: 2 guid: 5ab3fab12b464fde8a0870f50eb63227 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Event_NoParam/Event_Result/EventNoParamFloatResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Event No Param/Float Result", fileName = "event_no_param_float_result")] [EditorIcon("scriptable_event")] public class EventNoParamFloatResult : EventNoParamResult { } } ================================================ FILE: VirtueSky/Events/Runtime/Event_NoParam/Event_Result/EventNoParamFloatResult.cs.meta ================================================ fileFormatVersion: 2 guid: 6217d963db85402c9de627d2d8d69212 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Event_NoParam/Event_Result/EventNoParamGameObjectResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Event No Param/GameObject Result", fileName = "event_no_param_gameobject_result")] [EditorIcon("scriptable_event")] public class EventNoParamGameObjectResult : EventNoParamResult { } } ================================================ FILE: VirtueSky/Events/Runtime/Event_NoParam/Event_Result/EventNoParamGameObjectResult.cs.meta ================================================ fileFormatVersion: 2 guid: eb1a45f1342d4b8f9d3168c9bd787880 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Event_NoParam/Event_Result/EventNoParamIntResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Event No Param/Int Result", fileName = "event_no_param_int_result")] [EditorIcon("scriptable_event")] public class EventNoParamIntResult : EventNoParamResult { } } ================================================ FILE: VirtueSky/Events/Runtime/Event_NoParam/Event_Result/EventNoParamIntResult.cs.meta ================================================ fileFormatVersion: 2 guid: ef33b7c4a94e4d84a5c81533db50b708 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Event_NoParam/Event_Result/EventNoParamObjectResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Event No Param/Object Result", fileName = "event_no_param_object_result")] [EditorIcon("scriptable_event")] public class EventNoParamObjectResult : EventNoParamResult { } } ================================================ FILE: VirtueSky/Events/Runtime/Event_NoParam/Event_Result/EventNoParamObjectResult.cs.meta ================================================ fileFormatVersion: 2 guid: 59709cd40f054a9c9e0318ac778c56b7 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Event_NoParam/Event_Result/EventNoParamResult.cs ================================================ using VirtueSky.Core; using System; using UnityEditor; using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { public class EventNoParamResult : BaseSO, IEventNoParamResult { private Func onRaised = null; #if UNITY_EDITOR [Space(10)] [ShowIf(nameof(ConditionShow))] [ReadOnly, SerializeField] private TResult valueResult = default(TResult); [ShowIf(nameof(ConditionShow))] [Button("Raise")] private void DebugRaiseEvent() { valueResult = Raise(); } private bool ConditionShow => EditorApplication.isPlaying; #endif public TResult Raise() { TResult result = default; if (!Application.isPlaying) return result; if (onRaised != null) result = onRaised.Invoke(); return result; } public event Func OnRaised { add { onRaised += value; } remove { onRaised -= value; } } public void AddListener(Func func) { onRaised += func; } public void RemoveListener(Func func) { onRaised -= func; } public void RemoveAll() { onRaised = null; } } } ================================================ FILE: VirtueSky/Events/Runtime/Event_NoParam/Event_Result/EventNoParamResult.cs.meta ================================================ fileFormatVersion: 2 guid: 087399d034884472b66599ad570ef1ab timeCreated: 1709281627 ================================================ FILE: VirtueSky/Events/Runtime/Event_NoParam/Event_Result/EventNoParamStringResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Event No Param/String Result", fileName = "event_no_param_string_result")] [EditorIcon("scriptable_event")] public class EventNoParamStringResult : EventNoParamResult { } } ================================================ FILE: VirtueSky/Events/Runtime/Event_NoParam/Event_Result/EventNoParamStringResult.cs.meta ================================================ fileFormatVersion: 2 guid: aa172e3ef72c460a979b54431c5307dd MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Event_NoParam/Event_Result/EventNoParamTransformResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Event No Param/Transform Result", fileName = "event_no_param_transform_result")] [EditorIcon("scriptable_event")] public class EventNoParamTransformResult : EventNoParamResult { } } ================================================ FILE: VirtueSky/Events/Runtime/Event_NoParam/Event_Result/EventNoParamTransformResult.cs.meta ================================================ fileFormatVersion: 2 guid: 8aa6496b702641dca7fe9943e60e31d1 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Event_NoParam/Event_Result/EventNoParamVector3Result.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Event No Param/Vector3 Result", fileName = "event_no_param_vector3_result")] [EditorIcon("scriptable_event")] public class EventNoParamVector3Result : EventNoParamResult { } } ================================================ FILE: VirtueSky/Events/Runtime/Event_NoParam/Event_Result/EventNoParamVector3Result.cs.meta ================================================ fileFormatVersion: 2 guid: 8025d91ffb4749b58a33fbc7ff1a7e0e MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Event_NoParam/Event_Result.meta ================================================ fileFormatVersion: 2 guid: 0fc74cd12a235ff478703747992aa8c7 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Event_NoParam.meta ================================================ fileFormatVersion: 2 guid: 76a0de6e30e29514d8118075ea53f676 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Float_Event/Event_Result/FloatEventBoolResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Float Event/Bool Result", fileName = "float_event_bool_result")] [EditorIcon("scriptable_event")] public class FloatEventBoolResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Float_Event/Event_Result/FloatEventBoolResult.cs.meta ================================================ fileFormatVersion: 2 guid: 12bac208a97648528a05f68f30ec190f MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Float_Event/Event_Result/FloatEventFloatResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Float Event/Float Result", fileName = "float_event_float_result")] [EditorIcon("scriptable_event")] public class FloatEventFloatResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Float_Event/Event_Result/FloatEventFloatResult.cs.meta ================================================ fileFormatVersion: 2 guid: 1faa3b967231461f96ad3ac3386e910b MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Float_Event/Event_Result/FloatEventGameObjectResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Float Event/GameObject Result", fileName = "float_event_gameobject_result")] [EditorIcon("scriptable_event")] public class FloatEventGameObjectResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Float_Event/Event_Result/FloatEventGameObjectResult.cs.meta ================================================ fileFormatVersion: 2 guid: d47105243ada4cfd914307a3f05e5b98 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Float_Event/Event_Result/FloatEventIntResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Float Event/Int Result", fileName = "float_event_int_result")] [EditorIcon("scriptable_event")] public class FloatEventIntResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Float_Event/Event_Result/FloatEventIntResult.cs.meta ================================================ fileFormatVersion: 2 guid: 217cda72cf4046a4bbeee23128931457 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Float_Event/Event_Result/FloatEventObjectResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Float Event/Object Result", fileName = "float_event_object_result")] [EditorIcon("scriptable_event")] public class FloatEventObjectResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Float_Event/Event_Result/FloatEventObjectResult.cs.meta ================================================ fileFormatVersion: 2 guid: e05693d26cf54fa4bc61bc181433dc66 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Float_Event/Event_Result/FloatEventStringResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Float Event/String Result", fileName = "float_event_string_result")] [EditorIcon("scriptable_event")] public class FloatEventStringResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Float_Event/Event_Result/FloatEventStringResult.cs.meta ================================================ fileFormatVersion: 2 guid: 54165a581dbd462396f0915a4c6e54b1 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Float_Event/Event_Result/FloatEventTransformResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Float Event/Transform Result", fileName = "float_event_transform_result")] [EditorIcon("scriptable_event")] public class FloatEventTransformResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Float_Event/Event_Result/FloatEventTransformResult.cs.meta ================================================ fileFormatVersion: 2 guid: 9197e3ed49cf453e84a9f7f439d3b0c9 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Float_Event/Event_Result/FloatEventVector3Result.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Float Event/Vector3 Result", fileName = "float_event_vector3_result")] [EditorIcon("scriptable_event")] public class FloatEventVector3Result : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Float_Event/Event_Result/FloatEventVector3Result.cs.meta ================================================ fileFormatVersion: 2 guid: b4cd59a658ee41ae9a3918a871002a00 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Float_Event/Event_Result.meta ================================================ fileFormatVersion: 2 guid: 3117c81f14224bf3954e93ea3d3a3a03 timeCreated: 1708747781 ================================================ FILE: VirtueSky/Events/Runtime/Float_Event/FloatEvent.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event/Float Event", fileName = "float_event")] [EditorIcon("scriptable_event")] public class FloatEvent : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Float_Event/FloatEvent.cs.meta ================================================ fileFormatVersion: 2 guid: 0d8122074d0747c0bcac7e533000ff1e MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Float_Event/FloatEventListener.cs ================================================ using VirtueSky.Inspector; namespace VirtueSky.Events { [EditorIcon("scriptable_event_listener")] public class FloatEventListener : BaseEventListener { } } ================================================ FILE: VirtueSky/Events/Runtime/Float_Event/FloatEventListener.cs.meta ================================================ fileFormatVersion: 2 guid: 995103f2e8fb4e2b9b064c3d37181c3d MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 23cedf6c21faf0b4eb783f1fb5d4679a, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Float_Event/FloatEventResponse.cs ================================================ using System; namespace VirtueSky.Events { [Serializable] public class FloatEventResponse : BaseEventResponse { } } ================================================ FILE: VirtueSky/Events/Runtime/Float_Event/FloatEventResponse.cs.meta ================================================ fileFormatVersion: 2 guid: 36073394bda540afb4697e351c927583 timeCreated: 1651591152 ================================================ FILE: VirtueSky/Events/Runtime/Float_Event.meta ================================================ fileFormatVersion: 2 guid: ce1d9882ec91f6549b34f8364a1c68d6 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/GameObject_Event/Event_Result/GameObjectEventBoolResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/GameObject Event/Bool Result", fileName = "gameobject_event_bool_result")] [EditorIcon("scriptable_event")] public class GameObjectEventBoolResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/GameObject_Event/Event_Result/GameObjectEventBoolResult.cs.meta ================================================ fileFormatVersion: 2 guid: aa5eac033d974182bfd40eecb8ed40db MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/GameObject_Event/Event_Result/GameObjectEventFloatResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/GameObject Event/Float Result", fileName = "gameobject_event_float_result")] [EditorIcon("scriptable_event")] public class GameObjectEventFloatResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/GameObject_Event/Event_Result/GameObjectEventFloatResult.cs.meta ================================================ fileFormatVersion: 2 guid: 88fad7b13916467dae0ea470d7df09ec MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/GameObject_Event/Event_Result/GameObjectEventGameObjectResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/GameObject Event/GameObject Result", fileName = "gameobject_event_gameobject_result")] [EditorIcon("scriptable_event")] public class GameObjectEventGameObjectResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/GameObject_Event/Event_Result/GameObjectEventGameObjectResult.cs.meta ================================================ fileFormatVersion: 2 guid: 39fdab98b5e544eab00258ec356e3b71 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/GameObject_Event/Event_Result/GameObjectEventIntResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/GameObject Event/Int Result", fileName = "gameobject_event_int_result")] [EditorIcon("scriptable_event")] public class GameObjectEventIntResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/GameObject_Event/Event_Result/GameObjectEventIntResult.cs.meta ================================================ fileFormatVersion: 2 guid: 463d35d96c6348289d8d3cfb93ce1f80 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/GameObject_Event/Event_Result/GameObjectEventObjectResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/GameObject Event/Object Result", fileName = "gameobject_event_object_result")] [EditorIcon("scriptable_event")] public class GameObjectEventObjectResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/GameObject_Event/Event_Result/GameObjectEventObjectResult.cs.meta ================================================ fileFormatVersion: 2 guid: 81803ee8ec044a39adb56ac9ecd645e0 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/GameObject_Event/Event_Result/GameObjectEventStringResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/GameObject Event/String Result", fileName = "gameobject_event_string_result")] [EditorIcon("scriptable_event")] public class GameObjectEventStringResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/GameObject_Event/Event_Result/GameObjectEventStringResult.cs.meta ================================================ fileFormatVersion: 2 guid: 2886a83a3d8e48e8b9d5329973d8e208 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/GameObject_Event/Event_Result/GameObjectEventTransformResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/GameObject Event/Transform Result", fileName = "gameobject_event_transform_result")] [EditorIcon("scriptable_event")] public class GameObjectEventTransformResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/GameObject_Event/Event_Result/GameObjectEventTransformResult.cs.meta ================================================ fileFormatVersion: 2 guid: 8443a4df0b22415bab5d62b8859db1da MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/GameObject_Event/Event_Result/GameObjectEventVector3Result.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/GameObject Event/Vector3 Result", fileName = "gameobject_event_vector3_result")] [EditorIcon("scriptable_event")] public class GameObjectEventVector3Result : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/GameObject_Event/Event_Result/GameObjectEventVector3Result.cs.meta ================================================ fileFormatVersion: 2 guid: bd300e2220d84a23b8554d5fdae89945 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/GameObject_Event/Event_Result.meta ================================================ fileFormatVersion: 2 guid: 7e5bb96bd8b44401ba76bae7d0ac3c13 timeCreated: 1715332844 ================================================ FILE: VirtueSky/Events/Runtime/GameObject_Event/GameObjectEvent.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event/GameObject Event", fileName = "gameobject_event")] [EditorIcon("scriptable_event")] public class GameObjectEvent : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/GameObject_Event/GameObjectEvent.cs.meta ================================================ fileFormatVersion: 2 guid: 0a0508493bd04e4f92ca2a6213ac7808 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/GameObject_Event/GameObjectEventListener.cs ================================================ using UnityEngine; namespace VirtueSky.Events { public class GameObjectEventListener : BaseEventListener { } } ================================================ FILE: VirtueSky/Events/Runtime/GameObject_Event/GameObjectEventListener.cs.meta ================================================ fileFormatVersion: 2 guid: 05c7e72deb6b46cea123beeb0401340f timeCreated: 1715332800 ================================================ FILE: VirtueSky/Events/Runtime/GameObject_Event/GameObjectEventResponse.cs ================================================ using System; using UnityEngine; namespace VirtueSky.Events { [Serializable] public class GameObjectEventResponse : BaseEventResponse { } } ================================================ FILE: VirtueSky/Events/Runtime/GameObject_Event/GameObjectEventResponse.cs.meta ================================================ fileFormatVersion: 2 guid: 503b99c887194fe6be55014bd73779fc timeCreated: 1715332721 ================================================ FILE: VirtueSky/Events/Runtime/GameObject_Event.meta ================================================ fileFormatVersion: 2 guid: edc42b6d1574485f81087c5681e1cfa1 timeCreated: 1715332649 ================================================ FILE: VirtueSky/Events/Runtime/Integer_Event/Event_Result/IntEventBoolResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Int Event/Bool Result", fileName = "int_event_bool_result")] [EditorIcon("scriptable_event")] public class IntEventBoolResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Integer_Event/Event_Result/IntEventBoolResult.cs.meta ================================================ fileFormatVersion: 2 guid: 57d4e884db124e22afc24630ed354828 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Integer_Event/Event_Result/IntEventFloatResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Int Event/Float Result", fileName = "int_event_float_result")] [EditorIcon("scriptable_event")] public class IntEventFloatResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Integer_Event/Event_Result/IntEventFloatResult.cs.meta ================================================ fileFormatVersion: 2 guid: 00da8eff40dc476499c09b87b72c731c MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Integer_Event/Event_Result/IntEventGameObjectResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Int Event/GameObject Result", fileName = "int_event_gameobject_result")] [EditorIcon("scriptable_event")] public class IntEventGameObjectResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Integer_Event/Event_Result/IntEventGameObjectResult.cs.meta ================================================ fileFormatVersion: 2 guid: a573493495504c8f9ca82108fb849c14 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Integer_Event/Event_Result/IntEventIntResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Int Event/Int Result", fileName = "int_event_int_result")] [EditorIcon("scriptable_event")] public class IntEventIntResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Integer_Event/Event_Result/IntEventIntResult.cs.meta ================================================ fileFormatVersion: 2 guid: 5a6d60d18a2b4c1eb9946177245d7896 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Integer_Event/Event_Result/IntEventObjectResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Int Event/Object Result", fileName = "int_event_object_result")] [EditorIcon("scriptable_event")] public class IntEventObjectResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Integer_Event/Event_Result/IntEventObjectResult.cs.meta ================================================ fileFormatVersion: 2 guid: beff6470bcbe4db08054837335070f24 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Integer_Event/Event_Result/IntEventStringResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Int Event/String Result", fileName = "int_event_string_result")] [EditorIcon("scriptable_event")] public class IntEventStringResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Integer_Event/Event_Result/IntEventStringResult.cs.meta ================================================ fileFormatVersion: 2 guid: 8696075c48f345259d1bde0bff5572bf MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Integer_Event/Event_Result/IntEventTransformResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Int Event/Transform Result", fileName = "int_event_transform_result")] [EditorIcon("scriptable_event")] public class IntEventTransformResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Integer_Event/Event_Result/IntEventTransformResult.cs.meta ================================================ fileFormatVersion: 2 guid: b0e76b8386d1406fa58b31cec5547cd4 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Integer_Event/Event_Result/IntEventVector3Result.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Int Event/Vector3 Result", fileName = "int_event_vector3_result")] [EditorIcon("scriptable_event")] public class IntEventVector3Result : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Integer_Event/Event_Result/IntEventVector3Result.cs.meta ================================================ fileFormatVersion: 2 guid: 421cda8aa71a4df8aa65abb8f0cc58ed MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Integer_Event/Event_Result.meta ================================================ fileFormatVersion: 2 guid: 46b5110e766b4ae48a00f34d8a5f0254 timeCreated: 1708748301 ================================================ FILE: VirtueSky/Events/Runtime/Integer_Event/IntegerEvent.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event/Integer Event", fileName = "int_event")] [EditorIcon("scriptable_event")] public class IntegerEvent : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Integer_Event/IntegerEvent.cs.meta ================================================ fileFormatVersion: 2 guid: d6c2a70b0ee64462889213f36f37da24 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Integer_Event/IntegerEventListener.cs ================================================ using VirtueSky.Inspector; namespace VirtueSky.Events { [EditorIcon("scriptable_event_listener")] public class IntegerEventListener : BaseEventListener { } } ================================================ FILE: VirtueSky/Events/Runtime/Integer_Event/IntegerEventListener.cs.meta ================================================ fileFormatVersion: 2 guid: 16935cb5c30543f0b25ff56d4717ccf7 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 23cedf6c21faf0b4eb783f1fb5d4679a, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Integer_Event/IntegerEventResponse.cs ================================================ using System; namespace VirtueSky.Events { [Serializable] public class IntegerEventResponse : BaseEventResponse { } } ================================================ FILE: VirtueSky/Events/Runtime/Integer_Event/IntegerEventResponse.cs.meta ================================================ fileFormatVersion: 2 guid: 605bf97dd8cf41b1bd5be70b2a0c5c20 timeCreated: 1660313324 ================================================ FILE: VirtueSky/Events/Runtime/Integer_Event.meta ================================================ fileFormatVersion: 2 guid: 386df31c69ee5984985306e9013805ff folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Interface_Event/IEvent.cs ================================================ using System; namespace VirtueSky.Events { public interface IEvent { void Raise(); event Action OnRaised; void AddListener(Action action); void RemoveListener(Action action); void AddListener(IEventListener listener); void RemoveListener(IEventListener listener); void RemoveAll(); } public interface IEvent { void Raise(T value); event Action OnRaised; void AddListener(Action action); void RemoveListener(Action action); void AddListener(IEventListener listener); void RemoveListener(IEventListener listener); void RemoveAll(); } public interface IEvent { TResult Raise(T value); event Func OnRaised; void AddListener(Func func); void RemoveListener(Func func); void AddListener(IEventListener listener); void RemoveListener(IEventListener listener); void RemoveAll(); } public interface IEventNoParamResult { TResult Raise(); void AddListener(Func func); void RemoveListener(Func func); void RemoveAll(); } } ================================================ FILE: VirtueSky/Events/Runtime/Interface_Event/IEvent.cs.meta ================================================ fileFormatVersion: 2 guid: d2070d97c1045c34ea2aa99703681ff7 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Interface_Event/IEventListener.cs ================================================ using UnityEngine.Events; namespace VirtueSky.Events { public interface IEventListener { void OnEventRaised(BaseEvent eventRaise); } public interface IEventListener { void OnEventRaised(BaseEvent eventRaise, TType value); } public interface IEventListener { void OnEventRaised(BaseEvent eventRaise, TType value); } } ================================================ FILE: VirtueSky/Events/Runtime/Interface_Event/IEventListener.cs.meta ================================================ fileFormatVersion: 2 guid: ea776ff2b47efba45aaaa97cd1d5b0e1 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Interface_Event/IEventResponse.cs ================================================ namespace VirtueSky.Events { public interface IEventResponse { } } ================================================ FILE: VirtueSky/Events/Runtime/Interface_Event/IEventResponse.cs.meta ================================================ fileFormatVersion: 2 guid: d75ca69d3baf1944e9fcc175757ee9e8 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Interface_Event.meta ================================================ fileFormatVersion: 2 guid: c2cb5329047646c58e7e78be8462d33f timeCreated: 1697617947 ================================================ FILE: VirtueSky/Events/Runtime/Object_Event/Event_Result/ObjectEventBoolResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Object Event/Bool Result", fileName = "object_event_bool_result")] [EditorIcon("scriptable_event")] public class ObjectEventBoolResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Object_Event/Event_Result/ObjectEventBoolResult.cs.meta ================================================ fileFormatVersion: 2 guid: 10e6362f6a294bcdacd0c07553658839 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Object_Event/Event_Result/ObjectEventFloatResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Object Event/Float Result", fileName = "object_event_float_result")] [EditorIcon("scriptable_event")] public class ObjectEventFloatResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Object_Event/Event_Result/ObjectEventFloatResult.cs.meta ================================================ fileFormatVersion: 2 guid: 34ee83c58f53470a813e12dcbf0ed395 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Object_Event/Event_Result/ObjectEventGameObjectResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Object Event/GameObject Result", fileName = "object_event_gameobject_result")] [EditorIcon("scriptable_event")] public class ObjectEventGameObjectResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Object_Event/Event_Result/ObjectEventGameObjectResult.cs.meta ================================================ fileFormatVersion: 2 guid: 2a52416d28b1492b929cf20d9d68d446 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Object_Event/Event_Result/ObjectEventIntResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Object Event/Int Result", fileName = "object_event_int_result")] [EditorIcon("scriptable_event")] public class ObjectEventIntResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Object_Event/Event_Result/ObjectEventIntResult.cs.meta ================================================ fileFormatVersion: 2 guid: 650431f12c5f48048f25d88b3c177110 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Object_Event/Event_Result/ObjectEventObjectResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Object Event/Object Result", fileName = "object_event_object_result")] [EditorIcon("scriptable_event")] public class ObjectEventObjectResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Object_Event/Event_Result/ObjectEventObjectResult.cs.meta ================================================ fileFormatVersion: 2 guid: e2db6b1dbecf4682aa45d1b9283d264f MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Object_Event/Event_Result/ObjectEventStringResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Object Event/String Result", fileName = "object_event_string_result")] [EditorIcon("scriptable_event")] public class ObjectEventStringResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Object_Event/Event_Result/ObjectEventStringResult.cs.meta ================================================ fileFormatVersion: 2 guid: 0fdacef66d364fd7a04e8b228ccc77ed MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Object_Event/Event_Result/ObjectEventTransformResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Object Event/Transform Result", fileName = "object_event_transform_result")] [EditorIcon("scriptable_event")] public class ObjectEventTransformResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Object_Event/Event_Result/ObjectEventTransformResult.cs.meta ================================================ fileFormatVersion: 2 guid: 195e8386639d491a8cb5d5e4b6f84a1a MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Object_Event/Event_Result/ObjectEventVector3Result.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Object Event/Vector3 Result", fileName = "object_event_vector3_result")] [EditorIcon("scriptable_event")] public class ObjectEventVector3Result : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Object_Event/Event_Result/ObjectEventVector3Result.cs.meta ================================================ fileFormatVersion: 2 guid: 1747b009ef1942f3b43e1e64cf5afe54 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Object_Event/Event_Result.meta ================================================ fileFormatVersion: 2 guid: dd046df497e54574bbe1a3f576b1fe9c timeCreated: 1708748718 ================================================ FILE: VirtueSky/Events/Runtime/Object_Event/ObjectEvent.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event/Object Event", fileName = "object_event")] [EditorIcon("scriptable_event")] public class ObjectEvent : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Object_Event/ObjectEvent.cs.meta ================================================ fileFormatVersion: 2 guid: f13707fcbf06428493363549fe525368 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Object_Event/ObjectEventListener.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [EditorIcon("scriptable_event_listener")] public class ObjectEventListener : BaseEventListener { } } ================================================ FILE: VirtueSky/Events/Runtime/Object_Event/ObjectEventListener.cs.meta ================================================ fileFormatVersion: 2 guid: 6ff6677543cf4536a9f672e0851f915c MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 23cedf6c21faf0b4eb783f1fb5d4679a, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Object_Event/ObjectEventResponse.cs ================================================ using System; using Object = UnityEngine.Object; namespace VirtueSky.Events { [Serializable] public class ObjectEventResponse : BaseEventResponse { } } ================================================ FILE: VirtueSky/Events/Runtime/Object_Event/ObjectEventResponse.cs.meta ================================================ fileFormatVersion: 2 guid: ae05b91993734bc7b39f1dfe3e3c193e timeCreated: 1651590963 ================================================ FILE: VirtueSky/Events/Runtime/Object_Event.meta ================================================ fileFormatVersion: 2 guid: ef0ee8801f226b04f8dc9bf1f5fd28b3 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/ShortDouble_Event/ShortDoubleEvent.cs ================================================ using UnityEngine; using VirtueSky.DataType; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event/ShortDouble Event", fileName = "short_double_event")] [EditorIcon("scriptable_event")] public class ShortDoubleEvent : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/ShortDouble_Event/ShortDoubleEvent.cs.meta ================================================ fileFormatVersion: 2 guid: 8a3f4bf948b3823458a288ee16eab4d9 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/ShortDouble_Event/ShortDoubleEventListener.cs ================================================ using VirtueSky.DataType; using VirtueSky.Inspector; namespace VirtueSky.Events { [EditorIcon("scriptable_event_listener")] public class ShortDoubleEventListener : BaseEventListener { } } ================================================ FILE: VirtueSky/Events/Runtime/ShortDouble_Event/ShortDoubleEventListener.cs.meta ================================================ fileFormatVersion: 2 guid: 14a9ac023339adc48b39823e57aaab78 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 23cedf6c21faf0b4eb783f1fb5d4679a, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/ShortDouble_Event/ShortDoubleEventResponse.cs ================================================ using System; using VirtueSky.DataType; namespace VirtueSky.Events { [Serializable] public class ShortDoubleEventResponse : BaseEventResponse { } } ================================================ FILE: VirtueSky/Events/Runtime/ShortDouble_Event/ShortDoubleEventResponse.cs.meta ================================================ fileFormatVersion: 2 guid: 8a7944dec2527be48bb2003844a9428a MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/ShortDouble_Event.meta ================================================ fileFormatVersion: 2 guid: 048b8abc246701d479a0e54fd0a270cd folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/String_Event/Event_Result/StringEventBoolResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/String Event/Bool Result", fileName = "string_event_bool_result")] [EditorIcon("scriptable_event")] public class StringEventBoolResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/String_Event/Event_Result/StringEventBoolResult.cs.meta ================================================ fileFormatVersion: 2 guid: 35d4ff22e06d4ab4a89a6b1f1decebb6 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/String_Event/Event_Result/StringEventFloatResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/String Event/Float Result", fileName = "string_event_float_result")] [EditorIcon("scriptable_event")] public class StringEventFloatResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/String_Event/Event_Result/StringEventFloatResult.cs.meta ================================================ fileFormatVersion: 2 guid: 5d3802529d6a44a78187a8cdabda1805 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/String_Event/Event_Result/StringEventGameObjectResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/String Event/GameObject Result", fileName = "string_event_gameobject_result")] [EditorIcon("scriptable_event")] public class StringEventGameObjectResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/String_Event/Event_Result/StringEventGameObjectResult.cs.meta ================================================ fileFormatVersion: 2 guid: 9e409ad769e543158b91f676b0d0720c MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/String_Event/Event_Result/StringEventIntResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/String Event/Int Result", fileName = "string_event_int_result")] [EditorIcon("scriptable_event")] public class StringEventIntResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/String_Event/Event_Result/StringEventIntResult.cs.meta ================================================ fileFormatVersion: 2 guid: 7ba0cb3c0aa146b9969b921f592ca101 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/String_Event/Event_Result/StringEventObjectResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/String Event/Object Result", fileName = "string_event_object_result")] [EditorIcon("scriptable_event")] public class StringEventObjectResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/String_Event/Event_Result/StringEventObjectResult.cs.meta ================================================ fileFormatVersion: 2 guid: 1b74e192b77948c2af058a6e3893f2e4 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/String_Event/Event_Result/StringEventStringResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/String Event/String Result", fileName = "string_event_string_result")] [EditorIcon("scriptable_event")] public class StringEventStringResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/String_Event/Event_Result/StringEventStringResult.cs.meta ================================================ fileFormatVersion: 2 guid: 267b034fcb9b4283acb260745c1d7920 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/String_Event/Event_Result/StringEventTransformResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/String Event/Transform Result", fileName = "string_event_transform_result")] [EditorIcon("scriptable_event")] public class StringEventTransformResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/String_Event/Event_Result/StringEventTransformResult.cs.meta ================================================ fileFormatVersion: 2 guid: 681369168fd64ea085fa9204a2ec6a93 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/String_Event/Event_Result/StringEventVector3Result.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/String Event/Vector3 Result", fileName = "string_event_vector3_result")] [EditorIcon("scriptable_event")] public class StringEventVector3Result : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/String_Event/Event_Result/StringEventVector3Result.cs.meta ================================================ fileFormatVersion: 2 guid: 615d08d70aaa44d5841d124c0b92b351 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/String_Event/Event_Result.meta ================================================ fileFormatVersion: 2 guid: a14a9fe672404bd1bb8662de6d1f5512 timeCreated: 1708749207 ================================================ FILE: VirtueSky/Events/Runtime/String_Event/StringEvent.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event/String Event", fileName = "string_event")] [EditorIcon("scriptable_event")] public class StringEvent : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/String_Event/StringEvent.cs.meta ================================================ fileFormatVersion: 2 guid: 7403481dc1f5472fb389d85c74090ef5 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/String_Event/StringEventListener.cs ================================================ using VirtueSky.Inspector; namespace VirtueSky.Events { [EditorIcon("scriptable_event_listener")] public class StringEventListener : BaseEventListener { } } ================================================ FILE: VirtueSky/Events/Runtime/String_Event/StringEventListener.cs.meta ================================================ fileFormatVersion: 2 guid: 73a48105b6a944a69fe24790d53bbbea MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 23cedf6c21faf0b4eb783f1fb5d4679a, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/String_Event/StringEventResponse.cs ================================================ using System; namespace VirtueSky.Events { [Serializable] public class StringEventResponse : BaseEventResponse { } } ================================================ FILE: VirtueSky/Events/Runtime/String_Event/StringEventResponse.cs.meta ================================================ fileFormatVersion: 2 guid: 5b8a085f69174a3c9beeef25bb05bfd7 timeCreated: 1660273903 ================================================ FILE: VirtueSky/Events/Runtime/String_Event.meta ================================================ fileFormatVersion: 2 guid: d2bd365da6fd3ba43b04361c4c248a0e folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Transform_Event/Event_Result/TransformEventBoolResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Transform Event/Bool Result", fileName = "transform_event_bool_result")] [EditorIcon("scriptable_event")] public class TransformEventBoolResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Transform_Event/Event_Result/TransformEventBoolResult.cs.meta ================================================ fileFormatVersion: 2 guid: facbc86c28b44c769b2b9324a5c79e49 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Transform_Event/Event_Result/TransformEventFloatResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Transform Event/Float Result", fileName = "transform_event_float_result")] [EditorIcon("scriptable_event")] public class TransformEventFloatResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Transform_Event/Event_Result/TransformEventFloatResult.cs.meta ================================================ fileFormatVersion: 2 guid: 08f256c76831441db810c4fd37e6590d MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Transform_Event/Event_Result/TransformEventGameObjectResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Transform Event/GameObject Result", fileName = "transform_event_gameobject_result")] [EditorIcon("scriptable_event")] public class TransformEventGameObjectResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Transform_Event/Event_Result/TransformEventGameObjectResult.cs.meta ================================================ fileFormatVersion: 2 guid: 48fd269b7e264de4bfe4b8b7d5f7d2f3 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Transform_Event/Event_Result/TransformEventIntResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Transform Event/Int Result", fileName = "transform_event_int_result")] [EditorIcon("scriptable_event")] public class TransformEventIntResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Transform_Event/Event_Result/TransformEventIntResult.cs.meta ================================================ fileFormatVersion: 2 guid: e0371cf3d5d649df853e4beeda1d9931 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Transform_Event/Event_Result/TransformEventObjectResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Transform Event/Object Result", fileName = "transform_event_object_result")] [EditorIcon("scriptable_event")] public class TransformEventObjectResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Transform_Event/Event_Result/TransformEventObjectResult.cs.meta ================================================ fileFormatVersion: 2 guid: 5fbaf3c7a936483ca5f48cfa82b9edb9 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Transform_Event/Event_Result/TransformEventStringResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Transform Event/String Result", fileName = "transform_event_string_result")] [EditorIcon("scriptable_event")] public class TransformEventStringResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Transform_Event/Event_Result/TransformEventStringResult.cs.meta ================================================ fileFormatVersion: 2 guid: 1e50cf9550ac462286c3743afd086990 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Transform_Event/Event_Result/TransformEventTransformResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Transform Event/Transform Result", fileName = "transform_event_transform_result")] [EditorIcon("scriptable_event")] public class TransformEventTransformResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Transform_Event/Event_Result/TransformEventTransformResult.cs.meta ================================================ fileFormatVersion: 2 guid: 5be5e83df28340bf8b9c4fbcb2e8ef7f MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Transform_Event/Event_Result/TransformEventVector3Result.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Transform Event/Vector3 Result", fileName = "transform_event_vector3_result")] [EditorIcon("scriptable_event")] public class TransformEventVector3Result : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Transform_Event/Event_Result/TransformEventVector3Result.cs.meta ================================================ fileFormatVersion: 2 guid: 7f7e050901ff4e19b7e1735b1a513009 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Transform_Event/Event_Result.meta ================================================ fileFormatVersion: 2 guid: 8e33c282fc5443aa808f6f3dcc6cdbbf timeCreated: 1715331564 ================================================ FILE: VirtueSky/Events/Runtime/Transform_Event/TransformEvent.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event/Transform Event", fileName = "transform_event")] [EditorIcon("scriptable_event")] public class TransformEvent : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Transform_Event/TransformEvent.cs.meta ================================================ fileFormatVersion: 2 guid: af3a6d4bf4904719a9cbc9b60cea28df MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Transform_Event/TransformEventListener.cs ================================================ using UnityEngine; namespace VirtueSky.Events { public class TransformEventListener : BaseEventListener { } } ================================================ FILE: VirtueSky/Events/Runtime/Transform_Event/TransformEventListener.cs.meta ================================================ fileFormatVersion: 2 guid: 192621c184b4474faec0d2af15633658 timeCreated: 1715332518 ================================================ FILE: VirtueSky/Events/Runtime/Transform_Event/TransformEventResponse.cs ================================================ using System; using UnityEngine; namespace VirtueSky.Events { [Serializable] public class TransformEventResponse : BaseEventResponse { } } ================================================ FILE: VirtueSky/Events/Runtime/Transform_Event/TransformEventResponse.cs.meta ================================================ fileFormatVersion: 2 guid: 062600a2791448798d489dbe845ebec1 timeCreated: 1715332550 ================================================ FILE: VirtueSky/Events/Runtime/Transform_Event.meta ================================================ fileFormatVersion: 2 guid: 915ab2d6bede4928ac2e951849b36c90 timeCreated: 1715331546 ================================================ FILE: VirtueSky/Events/Runtime/Vector2_Event/Vector2Event.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event/Vector2 Event", fileName = "vector2_event")] [EditorIcon("scriptable_event")] public class Vector2Event : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Vector2_Event/Vector2Event.cs.meta ================================================ fileFormatVersion: 2 guid: 2e5819862aa24b89befaf72f9abdb43a MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Vector2_Event/Vector2EventListener.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [EditorIcon("scriptable_event_listener")] public class Vector2EventListener : BaseEventListener { } } ================================================ FILE: VirtueSky/Events/Runtime/Vector2_Event/Vector2EventListener.cs.meta ================================================ fileFormatVersion: 2 guid: b4b3354987d4441c9f741cff3f8b24f3 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 23cedf6c21faf0b4eb783f1fb5d4679a, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Vector2_Event/Vector2EventResponse.cs ================================================ using System; using UnityEngine; namespace VirtueSky.Events { [Serializable] public class Vector2EventResponse : BaseEventResponse { } } ================================================ FILE: VirtueSky/Events/Runtime/Vector2_Event/Vector2EventResponse.cs.meta ================================================ fileFormatVersion: 2 guid: ddb304bee5ca4681b3713b7c57c904f1 timeCreated: 1757604412 ================================================ FILE: VirtueSky/Events/Runtime/Vector2_Event.meta ================================================ fileFormatVersion: 2 guid: dded5e8cf8f94a078d77417a5e6f18e5 timeCreated: 1757604328 ================================================ FILE: VirtueSky/Events/Runtime/Vector3_Event/Event_Result/Vector3EventBoolResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Vector3 Event/Bool Result", fileName = "vector3_event_bool_result")] [EditorIcon("scriptable_event")] public class Vector3EventBoolResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Vector3_Event/Event_Result/Vector3EventBoolResult.cs.meta ================================================ fileFormatVersion: 2 guid: 2af53608ffba4530978d70a6f5ce42b5 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Vector3_Event/Event_Result/Vector3EventFloatResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Vector3 Event/Float Result", fileName = "vector3_event_float_result")] [EditorIcon("scriptable_event")] public class Vector3EventFloatResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Vector3_Event/Event_Result/Vector3EventFloatResult.cs.meta ================================================ fileFormatVersion: 2 guid: 8e1ff4b068344daa8f209370bb30bf9f MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Vector3_Event/Event_Result/Vector3EventGameObjectResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Vector3 Event/GameObject Result", fileName = "vector3_event_gameobject_result")] [EditorIcon("scriptable_event")] public class Vector3EventGameObjectResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Vector3_Event/Event_Result/Vector3EventGameObjectResult.cs.meta ================================================ fileFormatVersion: 2 guid: 096f83d658df425d9f0414d1503a7753 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Vector3_Event/Event_Result/Vector3EventIntResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Vector3 Event/Int Result", fileName = "vector3_event_int_result")] [EditorIcon("scriptable_event")] public class Vector3EventIntResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Vector3_Event/Event_Result/Vector3EventIntResult.cs.meta ================================================ fileFormatVersion: 2 guid: 4ef805eba18f450c8edc4dc7d808f9d6 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Vector3_Event/Event_Result/Vector3EventObjectResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Vector3 Event/Object Result", fileName = "vector3_event_object_result")] [EditorIcon("scriptable_event")] public class Vector3EventObjectResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Vector3_Event/Event_Result/Vector3EventObjectResult.cs.meta ================================================ fileFormatVersion: 2 guid: a24824336c6b49fbab7be100260b6f0f MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Vector3_Event/Event_Result/Vector3EventStringResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Vector3 Event/String Result", fileName = "vector3_event_string_result")] [EditorIcon("scriptable_event")] public class Vector3EventStringResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Vector3_Event/Event_Result/Vector3EventStringResult.cs.meta ================================================ fileFormatVersion: 2 guid: c84454eedc8f4fe4b1aa3ffa6f2a190f MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Vector3_Event/Event_Result/Vector3EventTransformResult.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Vector3 Event/Transform Result", fileName = "vector3_event_transform_result")] [EditorIcon("scriptable_event")] public class Vector3EventTransformResult : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Vector3_Event/Event_Result/Vector3EventTransformResult.cs.meta ================================================ fileFormatVersion: 2 guid: b1dffe3a46a54fb6bc240b1f98bf5d23 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Vector3_Event/Event_Result/Vector3EventVector3Result.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event-Result/Vector3 Event/Vector3 Result", fileName = "vector3_event_vector3_result")] [EditorIcon("scriptable_event")] public class Vector3EventVector3Result : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Vector3_Event/Event_Result/Vector3EventVector3Result.cs.meta ================================================ fileFormatVersion: 2 guid: 33d62a00e0d24e3b882b1a6f6530fb36 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Vector3_Event/Event_Result.meta ================================================ fileFormatVersion: 2 guid: 2f6b57e5e1004a45b8c066ba4b1cdb4c timeCreated: 1708763401 ================================================ FILE: VirtueSky/Events/Runtime/Vector3_Event/Vector3Event.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Event/Vector3 Event", fileName = "vector3_event")] [EditorIcon("scriptable_event")] public class Vector3Event : BaseEvent { } } ================================================ FILE: VirtueSky/Events/Runtime/Vector3_Event/Vector3Event.cs.meta ================================================ fileFormatVersion: 2 guid: 6204d80d69a942eeae93eff39c44aa91 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Vector3_Event/Vector3EventListener.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Events { [EditorIcon("scriptable_event_listener")] public class Vector3EventListener : BaseEventListener { } } ================================================ FILE: VirtueSky/Events/Runtime/Vector3_Event/Vector3EventListener.cs.meta ================================================ fileFormatVersion: 2 guid: 287ec16a80e0470794dd652b0c2636c6 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 23cedf6c21faf0b4eb783f1fb5d4679a, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/Vector3_Event/Vector3EventResponse.cs ================================================ using System; using UnityEngine; namespace VirtueSky.Events { [Serializable] public class Vector3EventResponse : BaseEventResponse { } } ================================================ FILE: VirtueSky/Events/Runtime/Vector3_Event/Vector3EventResponse.cs.meta ================================================ fileFormatVersion: 2 guid: 12ffc18fb6764f89a9271e41a8e1e24e timeCreated: 1660440731 ================================================ FILE: VirtueSky/Events/Runtime/Vector3_Event.meta ================================================ fileFormatVersion: 2 guid: 8f8affc2d416bcc4eb5e479d9c597184 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime/virtuesky.sunflower.event.asmdef ================================================ { "name": "Virtuesky.Sunflower.Event", "rootNamespace": "", "references": [ "GUID:acb3cac55c622ec459c8caadf707623a", "GUID:540154dd0c5ed9a4dbbe695c402232fb", "GUID:c904f6d969e991d459a0843b71c22ec5", "GUID:324caed91501a9c47a04ebfd87b68794" ], "includePlatforms": [], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], "versionDefines": [], "noEngineReferences": false } ================================================ FILE: VirtueSky/Events/Runtime/virtuesky.sunflower.event.asmdef.meta ================================================ fileFormatVersion: 2 guid: bd40169efe8642149b1d2b72ba4903ce AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events/Runtime.meta ================================================ fileFormatVersion: 2 guid: 41a3943bba6261d428d164cf82b35d24 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Events.meta ================================================ fileFormatVersion: 2 guid: 75f898c4077929444929383a64dde79b folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/FolderIcon/Editor/CustomFolder.cs ================================================ using System.IO; using UnityEditor; using UnityEngine; namespace Virtuesky.FolderIcon.Editor { [InitializeOnLoad] public class CustomFolder { static CustomFolder() { IconDictionaryCreator.BuildDictionary(); EditorApplication.projectWindowItemOnGUI -= DrawFolderIcon; EditorApplication.projectWindowItemOnGUI += DrawFolderIcon; } static void DrawFolderIcon(string guid, Rect rect) { if (IconDictionaryCreator.folderIconSettings == null || !IconDictionaryCreator.folderIconSettings.enableFolderIcons) return; var path = AssetDatabase.GUIDToAssetPath(guid); if (path == "" || Event.current.type != EventType.Repaint || !File.GetAttributes(path).HasFlag(FileAttributes.Directory) || !IconDictionaryCreator.folderIconSettings.folderIconsDictionary.ContainsKey(Path.GetFileName(path))) { return; } Rect imageRect; if (rect.height > 20) { imageRect = new Rect(rect.x - 1, rect.y - 1, rect.width + 2, rect.width + 2); } else if (rect.x > 20) { imageRect = new Rect(rect.x - 1, rect.y - 1, rect.height + 2, rect.height + 2); } else { imageRect = new Rect(rect.x + 2, rect.y - 1, rect.height + 2, rect.height + 2); } var texture = IconDictionaryCreator.folderIconSettings.folderIconsDictionary[Path.GetFileName(path)]; if (texture == null) { return; } GUI.DrawTexture(imageRect, texture); } } } ================================================ FILE: VirtueSky/FolderIcon/Editor/CustomFolder.cs.meta ================================================ fileFormatVersion: 2 guid: aac759806ab097f4c8e471a5f411afde MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/FolderIcon/Editor/FolderIconSettings.cs ================================================ using UnityEngine; using VirtueSky.DataType; using VirtueSky.Inspector; namespace Virtuesky.FolderIcon.Editor { [HideMonoScript] public class FolderIconSettings : ScriptableObject { public bool enableFolderIcons; public bool enableAutoCustomIconsDefault; [ShowIf(nameof(enableFolderIcons)), SerializeField] internal DictionaryCustom folderIconsDictionary; public void ClearCache() { folderIconsDictionary.Clear(); } public void OnValidate() { IconDictionaryCreator.BuildDictionary(); } } } ================================================ FILE: VirtueSky/FolderIcon/Editor/FolderIconSettings.cs.meta ================================================ fileFormatVersion: 2 guid: a1924e497ac37414e91f1284e084dc52 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/FolderIcon/Editor/IconDictionaryCreator.cs ================================================ using System.Collections.Generic; using System.IO; using UnityEditor; using UnityEngine; using VirtueSky.UtilsEditor; namespace Virtuesky.FolderIcon.Editor { public class IconDictionaryCreator : AssetPostprocessor { private const string AssetsPath = "/VirtueSky/FolderIcon/Icons"; internal static FolderIconSettings folderIconSettings; private static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths) { if (!ContainsIconAsset(importedAssets) && !ContainsIconAsset(deletedAssets) && !ContainsIconAsset(movedAssets) && !ContainsIconAsset(movedFromAssetPaths)) { return; } BuildDictionary(); } private static bool ContainsIconAsset(string[] assets) { foreach (string str in assets) { if (ReplaceSeparatorChar(Path.GetDirectoryName(str)) == FileExtension.GetPathFileInCurrentEnvironment(AssetsPath)) { return true; } } return false; } private static string ReplaceSeparatorChar(string path) { return path.Replace("\\", "/"); } internal static void BuildDictionary() { if (folderIconSettings == null) { folderIconSettings = CreateAsset.GetScriptableAsset(); } if (folderIconSettings != null && folderIconSettings.enableFolderIcons && folderIconSettings.enableAutoCustomIconsDefault) { var dir = new DirectoryInfo(FileExtension.GetPathFolderInCurrentEnvironment(AssetsPath)); FileInfo[] info = dir.GetFiles("*.png"); foreach (FileInfo f in info) { var texture = (Texture)AssetDatabase.LoadAssetAtPath( FileExtension.GetPathFileInCurrentEnvironment($"{AssetsPath}/{f.Name}"), typeof(Texture2D)); if (texture == null) continue; if (!folderIconSettings.folderIconsDictionary.ContainsKey(Path.GetFileNameWithoutExtension(f.Name))) { folderIconSettings.folderIconsDictionary.Add(Path.GetFileNameWithoutExtension(f.Name), texture); } } } } } } ================================================ FILE: VirtueSky/FolderIcon/Editor/IconDictionaryCreator.cs.meta ================================================ fileFormatVersion: 2 guid: 0a77cadbfb2c5454abdf50f2e809e1d9 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/FolderIcon/Editor/PackageIcon/icon_folder.unitypackage.meta ================================================ fileFormatVersion: 2 guid: ae8c4eb046f1efe4b8dbd578ca128018 DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/FolderIcon/Editor/PackageIcon.meta ================================================ fileFormatVersion: 2 guid: f515472d9efe0674c91f86231d70be03 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/FolderIcon/Editor/Virtuesky.Sunflower.FolderIcon.asmdef ================================================ { "name": "Virtuesky.Sunflower.FolderIcon", "rootNamespace": "", "references": [ "GUID:324caed91501a9c47a04ebfd87b68794", "GUID:c904f6d969e991d459a0843b71c22ec5", "GUID:540154dd0c5ed9a4dbbe695c402232fb" ], "includePlatforms": [ "Editor" ], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], "versionDefines": [], "noEngineReferences": false } ================================================ FILE: VirtueSky/FolderIcon/Editor/Virtuesky.Sunflower.FolderIcon.asmdef.meta ================================================ fileFormatVersion: 2 guid: 877be62fd20bbdb489dd86ee21cee87d AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/FolderIcon/Editor.meta ================================================ fileFormatVersion: 2 guid: 5e07d2c79a238874ba65d2d3c28e9932 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/FolderIcon/Icons/Animations.png.meta ================================================ fileFormatVersion: 2 guid: eab75b706f70aca43b8ff64634c515ee TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 1 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 1 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: WebGL maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: 51 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: 51 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/FolderIcon/Icons/Audio.png.meta ================================================ fileFormatVersion: 2 guid: 30b6f094fe545f640b5f5da798a13fb8 TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 1 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 1 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: WebGL maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: 51 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: 51 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/FolderIcon/Icons/Default/Default.png.meta ================================================ fileFormatVersion: 2 guid: 528e0cfe91970b64f9bf00466d825ed5 TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 1 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 1 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: WebGL maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: 51 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: 51 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/FolderIcon/Icons/Default.meta ================================================ fileFormatVersion: 2 guid: 8b577a1a895ebf649a74109c56ad6871 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/FolderIcon/Icons/Editor.png.meta ================================================ fileFormatVersion: 2 guid: 512d76f3dccd6f640b4ccc01cb61b756 TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 1 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 1 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: WebGL maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: 51 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: 51 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/FolderIcon/Icons/Fonts.png.meta ================================================ fileFormatVersion: 2 guid: 62ddbe7c7b650f349b033ff9fd3d0bff TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 1 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 1 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: WebGL maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: 51 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: 51 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/FolderIcon/Icons/Materials.png.meta ================================================ fileFormatVersion: 2 guid: 89dbba36a0719d24f9287029f9ee6587 TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 1 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 1 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: WebGL maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: 51 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: 51 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/FolderIcon/Icons/Models.png.meta ================================================ fileFormatVersion: 2 guid: 45ff670f2cb66164a8d6e10605691373 TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 1 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 1 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: WebGL maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: 51 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: 51 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/FolderIcon/Icons/Plugins.png.meta ================================================ fileFormatVersion: 2 guid: 13b91f0a2558c7048ad52ab46cbec5d9 TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 1 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 1 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: WebGL maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: 51 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: 51 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/FolderIcon/Icons/Prefabs.png.meta ================================================ fileFormatVersion: 2 guid: bb321d21ec6df16479b3b7ca2912c9c7 TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 1 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 1 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: WebGL maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: 51 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: 51 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/FolderIcon/Icons/Presets.png.meta ================================================ fileFormatVersion: 2 guid: 78eeb920cc73f444b874a012016e0aba TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 1 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 1 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: WebGL maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: 51 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: 51 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/FolderIcon/Icons/Resources.png.meta ================================================ fileFormatVersion: 2 guid: 9100ae07f3844b644a425dc2faa495b8 TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 1 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 1 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: WebGL maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: 51 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: 51 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/FolderIcon/Icons/Scenes.png.meta ================================================ fileFormatVersion: 2 guid: e883a49e0791ffb4da111b699600a550 TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 1 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 1 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: WebGL maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: 51 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: 51 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/FolderIcon/Icons/Scripts.png.meta ================================================ fileFormatVersion: 2 guid: 6e5375f7dc7dd98459edcd2fb9a3f8b5 TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 1 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 1 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: WebGL maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: 51 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: 51 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/FolderIcon/Icons/Settings.png.meta ================================================ fileFormatVersion: 2 guid: 3eeb12e1542f9da42815f009b4d9f05d TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 1 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 1 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: WebGL maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: 51 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: 51 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/FolderIcon/Icons/Shaders.png.meta ================================================ fileFormatVersion: 2 guid: 2bc839d7e3db2bf478572af026c7b8b4 TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 1 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 1 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: WebGL maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: 51 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: 51 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/FolderIcon/Icons/Sprites.png.meta ================================================ fileFormatVersion: 2 guid: b37da4319a2a50d4ebe3cc38697d9acf TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 1 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 1 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: WebGL maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: 51 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: 51 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/FolderIcon/Icons/Textures.png.meta ================================================ fileFormatVersion: 2 guid: cb4c49e67fb74904287e1799e8b3e47b TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 1 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 1 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: WebGL maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: 51 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 256 resizeAlgorithm: 0 textureFormat: 51 textureCompression: 2 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/FolderIcon/Icons.meta ================================================ fileFormatVersion: 2 guid: c1c3939351ff68442b9ebde71b3785b0 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/FolderIcon.meta ================================================ fileFormatVersion: 2 guid: e6b635d8cabe36a4384e73ea1b711728 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/GameService/Runtime/AppleAuthentication.cs ================================================ using System.Text; using UnityEngine; using VirtueSky.Events; using VirtueSky.Inspector; using VirtueSky.Variables; #if UNITY_IOS && VIRTUESKY_APPLE_AUTH using AppleAuth; using AppleAuth.Enums; using AppleAuth.Extensions; using AppleAuth.Interfaces; using AppleAuth.Native; #endif namespace VirtueSky.GameService { [EditorIcon("icon_authentication")] public class AppleAuthentication : ServiceAuthentication { [SerializeField] private StringVariable authorizationCodeVariable; [SerializeField] private StringVariable userIdVariable; [SerializeField] private EventNoParam tryLoginEvent; #if UNITY_IOS && VIRTUESKY_APPLE_AUTH private IAppleAuthManager _iAppleAuthManager; #endif protected override void Init() { #if UNITY_IOS && VIRTUESKY_APPLE_AUTH serverCode.Value = ""; authorizationCodeVariable.Value = ""; status.SetNotLoggedIn(); if (AppleAuthManager.IsCurrentPlatformSupported) { // Creates a default JSON deserializer, to transform JSON Native responses to C# instances var deserializer = new PayloadDeserializer(); // Creates an Apple Authentication manager with the deserializer this._iAppleAuthManager = new AppleAuthManager(deserializer); loginEvent.AddListener(Login); tryLoginEvent.AddListener(TryLogin); } #endif } private void Update() { #if UNITY_IOS && VIRTUESKY_APPLE_AUTH // Updates the AppleAuthManager instance to execute // pending callbacks inside Unity's execution loop if (this._iAppleAuthManager != null) { this._iAppleAuthManager.Update(); } #endif } protected override void Login() { #if UNITY_IOS && VIRTUESKY_APPLE_AUTH var loginArgs = new AppleAuthLoginArgs(LoginOptions.IncludeEmail | LoginOptions.IncludeFullName); this._iAppleAuthManager.LoginWithAppleId( loginArgs, credential => { // Obtained credential, cast it to IAppleIDCredential if (credential is IAppleIDCredential appleIdCredential) { // Apple User ID // You should save the user ID somewhere in the device var userId = appleIdCredential.User; // Email (Received ONLY in the first login) var email = appleIdCredential.Email; // Full name (Received ONLY in the first login) var fullName = appleIdCredential.FullName; // Identity token var identityToken = Encoding.UTF8.GetString( appleIdCredential.IdentityToken, 0, appleIdCredential.IdentityToken.Length); // Authorization code var authorizationCode = Encoding.UTF8.GetString( appleIdCredential.AuthorizationCode, 0, appleIdCredential.AuthorizationCode.Length); // And now you have all the information to create/login a user in your system serverCode.Value = identityToken; authorizationCodeVariable.Value = authorizationCode; userIdVariable.Value = userId; nameVariable.Value = $"{fullName.GivenName} {fullName.FamilyName}"; status.SetSuccessful(); } else { serverCode.Value = ""; userIdVariable.Value = ""; status.SetFailed(); } }, error => { // Something went wrong var authorizationErrorCode = error.GetAuthorizationErrorCode(); status.SetFailed(); }); #endif } /// /// Login when Apple credential still valid. /// private void TryLogin() { #if UNITY_IOS && VIRTUESKY_APPLE_AUTH if (string.IsNullOrEmpty(userIdVariable.Value)) return; this._iAppleAuthManager.GetCredentialState(userIdVariable.Value, state => { switch (state) { case CredentialState.Revoked: break; case CredentialState.Authorized: Debug.Log($"Apple credential still valid. Auto-login with userId: {userIdVariable.Value}"); Login(); break; case CredentialState.NotFound: Debug.LogWarning("Apple credential invalid or revoked."); userIdVariable.Value = ""; break; case CredentialState.Transferred: break; } }, error => { Debug.LogError("CredentialState check failed: " + error.ToString()); }); #endif } } } ================================================ FILE: VirtueSky/GameService/Runtime/AppleAuthentication.cs.meta ================================================ fileFormatVersion: 2 guid: f59cb8f4b8592824aa250e0ed64dfe29 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: e6bde4f6f44782647a9e30445fb10b74, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/GameService/Runtime/GooglePlayGamesAuthentication.cs ================================================ #if UNITY_ANDROID && VIRTUESKY_GPGS using GooglePlayGames; using GooglePlayGames.BasicApi; #endif using System.Threading.Tasks; using UnityEngine; using VirtueSky.Events; using VirtueSky.Inspector; namespace VirtueSky.GameService { [EditorIcon("icon_authentication")] public class GooglePlayGamesAuthentication : ServiceAuthentication { [SerializeField] private EventNoParam getNewServerCodeEvent; protected override void Init() { #if UNITY_ANDROID && VIRTUESKY_GPGS serverCode.Value = ""; status.SetNotLoggedIn(); PlayGamesPlatform.Activate(); loginEvent.AddListener(Login); getNewServerCodeEvent.AddListener(OnGetNewServerCode); #endif } #if UNITY_ANDROID && VIRTUESKY_GPGS private async void OnGetNewServerCode() { if (!PlayGamesPlatform.Instance.IsAuthenticated()) return; (serverCode.Value, status.Value) = await GetNewServerCode(); } private Task<(string, StatusLogin)> GetNewServerCode() { var taskSource = new TaskCompletionSource<(string, StatusLogin)>(); PlayGamesPlatform.Instance.RequestServerSideAccess(true, code => taskSource.SetResult((code, StatusLogin.Successful))); return taskSource.Task; } #endif protected override void Login() { #if UNITY_ANDROID && VIRTUESKY_GPGS PlayGamesPlatform.Instance.Authenticate((success) => { if (success == SignInStatus.Success) { Debug.Log("Login with Google Play games successful."); PlayGamesPlatform.Instance.RequestServerSideAccess(true, code => { Debug.Log("Authorization code: " + code); serverCode.Value = code; nameVariable.Value = PlayGamesPlatform.Instance.GetUserDisplayName(); status.SetSuccessful(); }); } else { PlayGamesPlatform.Instance.ManuallyAuthenticate(success => { if (success == SignInStatus.Success) { PlayGamesPlatform.Instance.RequestServerSideAccess(true, code => { Debug.Log("Authorization code: " + code); serverCode.Value = code; nameVariable.Value = PlayGamesPlatform.Instance.GetUserDisplayName(); status.SetSuccessful(); }); } else { Debug.Log("Login Failed"); serverCode.Value = ""; status.SetFailed(); } }); } }); #endif } public static bool IsSignIn() { #if UNITY_ANDROID && VIRTUESKY_GPGS return PlayGamesPlatform.Instance.IsAuthenticated(); #else return false; #endif } } } ================================================ FILE: VirtueSky/GameService/Runtime/GooglePlayGamesAuthentication.cs.meta ================================================ fileFormatVersion: 2 guid: 49195c8970f14421b92361f977eca22d MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: e6bde4f6f44782647a9e30445fb10b74, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/GameService/Runtime/ServiceAuthentication.cs ================================================ using UnityEngine; using VirtueSky.Events; using VirtueSky.Variables; #if UNITY_EDITOR using VirtueSky.UtilsEditor; #endif namespace VirtueSky.GameService { public abstract class ServiceAuthentication : MonoBehaviour { [SerializeField] private bool dontDestroyOnLoad; [SerializeField] protected StatusLoginVariable status; [SerializeField] protected StringVariable serverCode; [SerializeField] protected StringVariable nameVariable; [SerializeField] protected EventNoParam loginEvent; protected virtual void Awake() { if (dontDestroyOnLoad) { DontDestroyOnLoad(gameObject); } } private void Start() { Init(); } protected abstract void Init(); protected abstract void Login(); #if UNITY_EDITOR private void Reset() { status = CreateAsset.CreateAndGetScriptableAsset("/GameService", "status_login_variables"); } #endif } } ================================================ FILE: VirtueSky/GameService/Runtime/ServiceAuthentication.cs.meta ================================================ fileFormatVersion: 2 guid: f499843dccf345548b7dd3e954d94ffe timeCreated: 1722237144 ================================================ FILE: VirtueSky/GameService/Runtime/Variable/StatusLoginVariable.cs ================================================ using UnityEngine; using VirtueSky.Inspector; using VirtueSky.Variables; namespace VirtueSky.GameService { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Game Service/Status Login Variable", fileName = "status_login_variables")] [EditorIcon("scriptable_variable")] public class StatusLoginVariable : BaseVariable { public void SetNotLoggedIn() { Value = StatusLogin.NotLoggedIn; } public void SetSuccessful() { Value = StatusLogin.Successful; } public void SetFailed() { Value = StatusLogin.Failed; } } public enum StatusLogin { NotLoggedIn, Successful, Failed } } ================================================ FILE: VirtueSky/GameService/Runtime/Variable/StatusLoginVariable.cs.meta ================================================ fileFormatVersion: 2 guid: 63fab0e810474ad9bd48cc760d1311b2 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 8f06818ab5c1c06439abc547979c8edd, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/GameService/Runtime/Variable.meta ================================================ fileFormatVersion: 2 guid: bd3fa253ca6846bab2521d35555ff162 timeCreated: 1722240964 ================================================ FILE: VirtueSky/GameService/Runtime/Virtuesky.Sunflower.GameService.asmdef ================================================ { "name": "Virtuesky.Sunflower.GameService", "rootNamespace": "", "references": [ "GUID:bd40169efe8642149b1d2b72ba4903ce", "GUID:1ed07ff861e5f468287b0baef844706d", "GUID:acb3cac55c622ec459c8caadf707623a", "GUID:e2146bdc04d424169b039613a1b62bdf", "GUID:35d694408290717499b3838802212c7f", "GUID:324caed91501a9c47a04ebfd87b68794", "GUID:c904f6d969e991d459a0843b71c22ec5" ], "includePlatforms": [], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], "versionDefines": [], "noEngineReferences": false } ================================================ FILE: VirtueSky/GameService/Runtime/Virtuesky.Sunflower.GameService.asmdef.meta ================================================ fileFormatVersion: 2 guid: 2356c024261911440b11bc0bf55f4d5d AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/GameService/Runtime.meta ================================================ fileFormatVersion: 2 guid: d7d242c8225bfc94cbb90a295f94c806 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/GameService.meta ================================================ fileFormatVersion: 2 guid: 0dfa84c557cc1d24ea633af32cdb75cc folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Hierarchy/Attribute/HierarchyNullable.asmdef ================================================ { "name": "HierarchyNullable", "rootNamespace": "", "references": [], "includePlatforms": [], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], "versionDefines": [], "noEngineReferences": false } ================================================ FILE: VirtueSky/Hierarchy/Attribute/HierarchyNullable.asmdef.meta ================================================ fileFormatVersion: 2 guid: 784c1df74834cb743a426a6126f1064d AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Hierarchy/Attribute/HierarchyNullable.cs ================================================ using UnityEngine; public class HierarchyNullableAttribute : PropertyAttribute { } ================================================ FILE: VirtueSky/Hierarchy/Attribute/HierarchyNullable.cs.meta ================================================ fileFormatVersion: 2 guid: 15892d7337a046e43b2c6bad21242c1a MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Hierarchy/Attribute.meta ================================================ fileFormatVersion: 2 guid: 602672b16b2911c47892de4f436d5894 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Hierarchy/Editor/HierarchyEditor.asmdef ================================================ { "name": "HierarchyEditor", "rootNamespace": "", "references": [ "Virtuesky.Sunflower.DataStorage.Editor", "VirtueSky.Sunflower.Inspector", "HierarchyNullable", "HierarchyRuntime", "Virtuesky.Sunflower.UtilsEdtitor" ], "includePlatforms": [ "Editor" ], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], "versionDefines": [], "noEngineReferences": false } ================================================ FILE: VirtueSky/Hierarchy/Editor/HierarchyEditor.asmdef.meta ================================================ fileFormatVersion: 2 guid: 49674d15b25185649b7ec8ac5d378747 AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Component/Base/BaseComponent.cs ================================================ using UnityEngine; using System; using System.Collections.Generic; using VirtueSky.Hierarchy; namespace VirtueSky.Hierarchy.HComponent.Base { public enum LayoutStatus { Success, Partly, Failed, } public class BaseComponent { // PUBLIC public Rect rect = new Rect(0, 0, 16, 16); // PRIVATE protected bool enabled = false; protected bool showComponentDuringPlayMode = false; // CONSTRUCTOR public BaseComponent() { } // PUBLIC public virtual LayoutStatus layout(GameObject gameObject, ObjectList objectList, Rect selectionRect, ref Rect curRect, float maxWidth) { return LayoutStatus.Success; } public virtual void draw(GameObject gameObject, ObjectList objectList, Rect selectionRect) { } public virtual void eventHandler(GameObject gameObject, ObjectList objectList, Event currentEvent) { } public virtual void disabledHandler(GameObject gameObject, ObjectList objectList) { } public virtual void setEnabled(bool value) { this.enabled = value; } public virtual bool isEnabled() { if (!enabled) { return false; } else { if (Application.isPlaying) return showComponentDuringPlayMode; else return true; } } // PROTECTED protected void getGameObjectListRecursive(GameObject gameObject, ref Listresult, int maxDepth = int.MaxValue) { result.Add(gameObject); if (maxDepth > 0) { Transform transform = gameObject.transform; for (int i = transform.childCount - 1; i >= 0; i--) getGameObjectListRecursive(transform.GetChild(i).gameObject, ref result, maxDepth - 1); } } } } ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Component/Base/BaseComponent.cs.meta ================================================ fileFormatVersion: 2 guid: 0276e09a5dfa026458af52fb4ee838d2 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Component/Base.meta ================================================ fileFormatVersion: 2 guid: bf7b2f59a50ea694b898adc34d520d86 folderAsset: yes timeCreated: 1515657177 licenseType: Store DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Component/ChildrenCountComponent.cs ================================================ using System; using System.Collections.Generic; using UnityEngine; using UnityEditor; using VirtueSky.Hierarchy.HComponent.Base; using VirtueSky.Hierarchy; using VirtueSky.Hierarchy.Helper; using VirtueSky.Hierarchy.Data; namespace VirtueSky.Hierarchy.HComponent { public class ChildrenCountComponent: BaseComponent { // PRIVATE private GUIStyle labelStyle; // CONSTRUCTOR public ChildrenCountComponent () { labelStyle = new GUIStyle(); labelStyle.fontSize = 9; labelStyle.clipping = TextClipping.Clip; labelStyle.alignment = TextAnchor.MiddleRight; rect.width = 22; rect.height = 16; HierarchySettings.getInstance().addEventListener(HierarchySetting.ChildrenCountShow , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.ChildrenCountShowDuringPlayMode, settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.ChildrenCountLabelSize , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.ChildrenCountLabelColor , settingsChanged); settingsChanged(); } // PRIVATE private void settingsChanged() { enabled = HierarchySettings.getInstance().get(HierarchySetting.ChildrenCountShow); showComponentDuringPlayMode = HierarchySettings.getInstance().get(HierarchySetting.ChildrenCountShowDuringPlayMode); HierarchySize labelSize = (HierarchySize)HierarchySettings.getInstance().get(HierarchySetting.ChildrenCountLabelSize); labelStyle.normal.textColor = HierarchySettings.getInstance().getColor(HierarchySetting.ChildrenCountLabelColor); labelStyle.fontSize = labelSize == HierarchySize.Normal ? 8 : 9; rect.width = labelSize == HierarchySize.Normal ? 17 : 22; } // DRAW public override LayoutStatus layout(GameObject gameObject, ObjectList objectList, Rect selectionRect, ref Rect curRect, float maxWidth) { if (maxWidth < rect.width) { return LayoutStatus.Failed; } else { curRect.x -= rect.width + 2; rect.x = curRect.x; rect.y = curRect.y; rect.y += (EditorGUIUtility.singleLineHeight - rect.height) * 0.5f; rect.height = EditorGUIUtility.singleLineHeight; return LayoutStatus.Success; } } public override void draw(GameObject gameObject, ObjectList objectList, Rect selectionRect) { int childrenCount = gameObject.transform.childCount; if (childrenCount > 0) GUI.Label(rect, childrenCount.ToString(), labelStyle); } } } ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Component/ChildrenCountComponent.cs.meta ================================================ fileFormatVersion: 2 guid: 2f1b06ed245a831438a2f155f068dd8a MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Component/ColorComponent.cs ================================================ using System; using System.Collections.Generic; using UnityEngine; using UnityEditor; using VirtueSky.Hierarchy.HComponent.Base; using VirtueSky.Hierarchy.Data; using VirtueSky.Hierarchy.Helper; namespace VirtueSky.Hierarchy.HComponent { public class ColorComponent: BaseComponent { // PRIVATE private Color inactiveColor; private Texture2D colorTexture; private Rect colorRect = new Rect(); // CONSTRUCTOR public ColorComponent() { colorTexture = HierarchyResources.getInstance().getTexture(HierarchyTexture.HierarchyColorButton); rect.width = 8; rect.height = 16; HierarchySettings.getInstance().addEventListener(HierarchySetting.ColorShow , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.ColorShowDuringPlayMode, settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.AdditionalInactiveColor, settingsChanged); settingsChanged(); } // PRIVATE private void settingsChanged() { enabled = HierarchySettings.getInstance().get(HierarchySetting.ColorShow); showComponentDuringPlayMode = HierarchySettings.getInstance().get(HierarchySetting.ColorShowDuringPlayMode); inactiveColor = HierarchySettings.getInstance().getColor(HierarchySetting.AdditionalInactiveColor); } // LAYOUT public override LayoutStatus layout(GameObject gameObject, ObjectList objectList, Rect selectionRect, ref Rect curRect, float maxWidth) { if (maxWidth < 8) { return LayoutStatus.Failed; } else { curRect.x -= 8; rect.x = curRect.x; rect.y = curRect.y; return LayoutStatus.Success; } } // DRAW public override void draw(GameObject gameObject, ObjectList objectList, Rect selectionRect) { if (objectList != null) { Color newColor; if (objectList.gameObjectColor.TryGetValue(gameObject, out newColor)) { colorRect.Set(rect.x + 1, rect.y + 1, 5, rect.height - 1); EditorGUI.DrawRect(colorRect, newColor); return; } } HierarchyColorUtils.setColor(inactiveColor); GUI.DrawTexture(rect, colorTexture, ScaleMode.StretchToFill, true, 1); HierarchyColorUtils.clearColor(); } // EVENTS public override void eventHandler(GameObject gameObject, ObjectList objectList, Event currentEvent) { if (currentEvent.isMouse && currentEvent.type == EventType.MouseDown && currentEvent.button == 0 && rect.Contains(currentEvent.mousePosition)) { if (currentEvent.type == EventType.MouseDown) { try { PopupWindow.Show(rect, new HierarchyColorPickerWindow(Selection.Contains(gameObject) ? Selection.gameObjects : new GameObject[] { gameObject }, colorSelectedHandler, colorRemovedHandler)); } catch {} } currentEvent.Use(); } } // PRIVATE private void colorSelectedHandler(GameObject[] gameObjects, Color color) { for (int i = gameObjects.Length - 1; i >= 0; i--) { GameObject gameObject = gameObjects[i]; ObjectList objectList = HierarchyObjectListManager.getInstance().getObjectList(gameObjects[i], true); Undo.RecordObject(objectList, "Color Changed"); if (objectList.gameObjectColor.ContainsKey(gameObject)) { objectList.gameObjectColor[gameObject] = color; } else { objectList.gameObjectColor.Add(gameObject, color); } } EditorApplication.RepaintHierarchyWindow(); } private void colorRemovedHandler(GameObject[] gameObjects) { for (int i = gameObjects.Length - 1; i >= 0; i--) { GameObject gameObject = gameObjects[i]; ObjectList objectList = HierarchyObjectListManager.getInstance().getObjectList(gameObjects[i], true); if (objectList.gameObjectColor.ContainsKey(gameObject)) { Undo.RecordObject(objectList, "Color Changed"); objectList.gameObjectColor.Remove(gameObject); } } EditorApplication.RepaintHierarchyWindow(); } } } ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Component/ColorComponent.cs.meta ================================================ fileFormatVersion: 2 guid: 335f808a233353e49826c77694c5a31c MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Component/ComponentsComponent.cs ================================================ using System; using System.Reflection; using System.Collections.Generic; using UnityEngine; using UnityEditor; using VirtueSky.Hierarchy.HComponent.Base; using VirtueSky.Hierarchy.Data; using VirtueSky.Hierarchy.Helper; namespace VirtueSky.Hierarchy.HComponent { public class ComponentsComponent: BaseComponent { // PRIVATE private GUIStyle hintLabelStyle; private Color grayColor; private Color backgroundDarkColor; private Texture2D componentIcon; private List components = new List(); private Rect eventRect = new Rect(0, 0, 16, 16); private int componentsToDraw; private List ignoreScripts; // CONSTRUCTOR public ComponentsComponent () { this.backgroundDarkColor = HierarchyResources.getInstance().getColor(HierarchyColor.BackgroundDark); this.grayColor = HierarchyResources.getInstance().getColor(HierarchyColor.Gray); this.componentIcon = HierarchyResources.getInstance().getTexture(HierarchyTexture.HierarchyComponentUnknownIcon); hintLabelStyle = new GUIStyle(); hintLabelStyle.normal.textColor = grayColor; hintLabelStyle.fontSize = 11; hintLabelStyle.clipping = TextClipping.Clip; HierarchySettings.getInstance().addEventListener(HierarchySetting.ComponentsShow , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.ComponentsShowDuringPlayMode, settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.ComponentsIconSize , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.ComponentsIgnore , settingsChanged); settingsChanged(); } // PRIVATE private void settingsChanged() { enabled = HierarchySettings.getInstance().get(HierarchySetting.ComponentsShow); showComponentDuringPlayMode = HierarchySettings.getInstance().get(HierarchySetting.ComponentsShowDuringPlayMode); HierarchySizeAll size = (HierarchySizeAll)HierarchySettings.getInstance().get(HierarchySetting.ComponentsIconSize); rect.width = rect.height = (size == HierarchySizeAll.Normal ? 15 : (size == HierarchySizeAll.Big ? 16 : 13)); string ignoreString = HierarchySettings.getInstance().get(HierarchySetting.ComponentsIgnore); if (ignoreString != "") { ignoreScripts = new List(ignoreString.Split(new char[] { ',', ';', '.', ' ' })); ignoreScripts.RemoveAll(item => item == ""); } else ignoreScripts = null; } // DRAW public override LayoutStatus layout(GameObject gameObject, ObjectList objectList, Rect selectionRect, ref Rect curRect, float maxWidth) { Component[] currentComponents = gameObject.GetComponents(); components.Clear(); if (ignoreScripts != null) { for (int i = 0; i < currentComponents.Length; i++) { string componentName = currentComponents[i].GetType().FullName; bool ignore = false; for (int j = ignoreScripts.Count - 1; j >= 0; j--) { if (componentName.Contains(ignoreScripts[j])) { ignore = true; break; } } if (!ignore) components.Add(currentComponents[i]); } } else { components.AddRange(currentComponents); } int maxComponentsCount = Mathf.FloorToInt((maxWidth - 2) / rect.width); componentsToDraw = Math.Min(maxComponentsCount, components.Count - 1); float totalWidth = 2 + rect.width * componentsToDraw; curRect.x -= totalWidth; rect.x = curRect.x; rect.y = curRect.y - (rect.height - 16) / 2; eventRect.width = totalWidth; eventRect.x = rect.x; eventRect.y = rect.y; if (maxComponentsCount >= components.Count - 1) return LayoutStatus.Success; else if (maxComponentsCount == 0) return LayoutStatus.Failed; else return LayoutStatus.Partly; } public override void draw(GameObject gameObject, ObjectList objectList, Rect selectionRect) { for (int i = components.Count - componentsToDraw, n = components.Count; i < n; i++) { Component component = components[i]; if (component is Transform) continue; GUIContent content = EditorGUIUtility.ObjectContent(component, null); bool enabled = true; try { PropertyInfo propertyInfo = component.GetType().GetProperty("enabled"); enabled = (bool)propertyInfo.GetGetMethod().Invoke(component, null); } catch {} Color color = GUI.color; color.a = enabled ? 1f : 0.3f; GUI.color = color; GUI.DrawTexture(rect, content.image == null ? componentIcon : content.image, ScaleMode.ScaleToFit); color.a = 1; GUI.color = color; if (rect.Contains(Event.current.mousePosition)) { string componentName = "Missing script"; if (component != null) componentName = component.GetType().Name; int labelWidth = Mathf.CeilToInt(hintLabelStyle.CalcSize(new GUIContent(componentName)).x); selectionRect.x = rect.x - labelWidth / 2 - 4; selectionRect.width = labelWidth + 8; selectionRect.height -= 1; if (selectionRect.y > 16) selectionRect.y -= 16; else selectionRect.x += labelWidth / 2 + 18; EditorGUI.DrawRect(selectionRect, backgroundDarkColor); selectionRect.x += 4; selectionRect.y += (EditorGUIUtility.singleLineHeight - rect.height) * 0.5f; selectionRect.height = EditorGUIUtility.singleLineHeight; EditorGUI.LabelField(selectionRect, componentName, hintLabelStyle); } rect.x += rect.width; } } public override void eventHandler(GameObject gameObject, ObjectList objectList, Event currentEvent) { if (currentEvent.isMouse && currentEvent.button == 0 && eventRect.Contains(currentEvent.mousePosition)) { if (currentEvent.type == EventType.MouseDown) { int id = Mathf.FloorToInt((currentEvent.mousePosition.x - eventRect.x) / rect.width) + components.Count - 1 - componentsToDraw + 1; try { PropertyInfo propertyInfo = components[id].GetType().GetProperty("enabled"); bool enabled = (bool)propertyInfo.GetGetMethod().Invoke(components[id], null); Undo.RecordObject(components[id], enabled ? "Disable Component" : "Enable Component"); propertyInfo.GetSetMethod().Invoke(components[id], new object[] { !enabled }); } catch {} EditorUtility.SetDirty(gameObject); } currentEvent.Use(); } } } } ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Component/ComponentsComponent.cs.meta ================================================ fileFormatVersion: 2 guid: b711e39572aded64d92872ed8343ffb3 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Component/ErrorComponent.cs ================================================ using System; using System.Collections.Generic; using UnityEngine; using UnityEditor; using UnityEngine.Events; using VirtueSky.Hierarchy.HComponent.Base; using VirtueSky.Hierarchy; using VirtueSky.Hierarchy.Helper; using VirtueSky.Hierarchy.Data; using System.Reflection; using System.Collections; using UnityEditorInternal; using System.Text; namespace VirtueSky.Hierarchy.HComponent { public class ErrorComponent : BaseComponent { // PRIVATE private Color activeColor; private Color inactiveColor; private Texture2D errorIconTexture; private bool showErrorOfChildren; private bool showErrorTypeReferenceIsNull; private bool showErrorTypeReferenceIsMissing; private bool showErrorTypeStringIsEmpty; private bool showErrorIconScriptIsMissing; private bool showErrorIconWhenTagIsUndefined; private bool showErrorForDisabledComponents; private bool showErrorIconMissingEventMethod; private bool showErrorForDisabledGameObjects; private List ignoreErrorOfMonoBehaviours; private StringBuilder errorStringBuilder; private int errorCount; // CONSTRUCTOR public ErrorComponent() { rect.width = 7; errorIconTexture = HierarchyResources.getInstance().getTexture(HierarchyTexture.HierarchyErrorIcon); HierarchySettings.getInstance().addEventListener(HierarchySetting.ErrorShowIconOnParent, settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.ErrorShowReferenceIsNull, settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.ErrorShowReferenceIsMissing, settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.ErrorShowStringIsEmpty, settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.ErrorShowScriptIsMissing, settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.ErrorShowForDisabledComponents, settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.ErrorShowForDisabledGameObjects, settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.ErrorShowMissingEventMethod, settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.ErrorShowWhenTagOrLayerIsUndefined, settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.ErrorShow, settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.ErrorShowDuringPlayMode, settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.ErrorIgnoreString, settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.AdditionalActiveColor, settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.AdditionalInactiveColor, settingsChanged); settingsChanged(); } // PRIVATE private void settingsChanged() { showErrorOfChildren = HierarchySettings.getInstance().get(HierarchySetting.ErrorShowIconOnParent); showErrorTypeReferenceIsNull = HierarchySettings.getInstance().get(HierarchySetting.ErrorShowReferenceIsNull); showErrorTypeReferenceIsMissing = HierarchySettings.getInstance().get(HierarchySetting.ErrorShowReferenceIsMissing); showErrorTypeStringIsEmpty = HierarchySettings.getInstance().get(HierarchySetting.ErrorShowStringIsEmpty); showErrorIconScriptIsMissing = HierarchySettings.getInstance().get(HierarchySetting.ErrorShowScriptIsMissing); showErrorForDisabledComponents = HierarchySettings.getInstance().get(HierarchySetting.ErrorShowForDisabledComponents); showErrorForDisabledGameObjects = HierarchySettings.getInstance().get(HierarchySetting.ErrorShowForDisabledGameObjects); showErrorIconMissingEventMethod = HierarchySettings.getInstance().get(HierarchySetting.ErrorShowMissingEventMethod); showErrorIconWhenTagIsUndefined = HierarchySettings.getInstance().get(HierarchySetting.ErrorShowWhenTagOrLayerIsUndefined); activeColor = HierarchySettings.getInstance().getColor(HierarchySetting.AdditionalActiveColor); inactiveColor = HierarchySettings.getInstance().getColor(HierarchySetting.AdditionalInactiveColor); enabled = HierarchySettings.getInstance().get(HierarchySetting.ErrorShow); showComponentDuringPlayMode = HierarchySettings.getInstance().get(HierarchySetting.ErrorShowDuringPlayMode); string ignoreErrorOfMonoBehavioursString = HierarchySettings.getInstance().get(HierarchySetting.ErrorIgnoreString); if (ignoreErrorOfMonoBehavioursString != "") { ignoreErrorOfMonoBehaviours = new List(ignoreErrorOfMonoBehavioursString.Split(new char[] { ',', ';', '.', ' ' })); ignoreErrorOfMonoBehaviours.RemoveAll(item => item == ""); } else ignoreErrorOfMonoBehaviours = null; } // DRAW public override LayoutStatus layout(GameObject gameObject, ObjectList objectList, Rect selectionRect, ref Rect curRect, float maxWidth) { if (maxWidth < 7) { return LayoutStatus.Failed; } else { curRect.x -= 7; rect.x = curRect.x; rect.y = curRect.y; return LayoutStatus.Success; } } public override void draw(GameObject gameObject, ObjectList objectList, Rect selectionRect) { bool errorFound = findError(gameObject, gameObject.GetComponents()); if (errorFound) { HierarchyColorUtils.setColor(activeColor); GUI.DrawTexture(rect, errorIconTexture); HierarchyColorUtils.clearColor(); } else if (showErrorOfChildren) { errorFound = findError(gameObject, gameObject.GetComponentsInChildren(true)); if (errorFound) { HierarchyColorUtils.setColor(inactiveColor); GUI.DrawTexture(rect, errorIconTexture); HierarchyColorUtils.clearColor(); } } } public override void eventHandler(GameObject gameObject, ObjectList objectList, Event currentEvent) { if (currentEvent.isMouse && currentEvent.type == EventType.MouseDown && currentEvent.button == 0 && rect.Contains(currentEvent.mousePosition)) { currentEvent.Use(); errorCount = 0; errorStringBuilder = new StringBuilder(); findError(gameObject, gameObject.GetComponents(), true); if (errorCount > 0) { EditorUtility.DisplayDialog( errorCount + (errorCount == 1 ? " error was found" : " errors were found"), errorStringBuilder.ToString(), "OK"); } } } // PRIVATE private bool findError(GameObject gameObject, MonoBehaviour[] components, bool printError = false) { if (showErrorIconWhenTagIsUndefined) { try { gameObject.tag.CompareTo(null); } catch { if (printError) { appendErrorLine("Tag is undefined"); } else { return true; } } if (LayerMask.LayerToName(gameObject.layer).Equals("")) { if (printError) { appendErrorLine("Layer is undefined"); } else { return true; } } } for (int i = 0; i < components.Length; i++) { MonoBehaviour monoBehaviour = components[i]; if (monoBehaviour == null) { if (showErrorIconScriptIsMissing) { if (printError) { appendErrorLine("Component #" + i + " is missing"); } else { return true; } } } else { if (ignoreErrorOfMonoBehaviours != null) { for (int j = ignoreErrorOfMonoBehaviours.Count - 1; j >= 0; j--) { if (monoBehaviour.GetType().FullName.Contains(ignoreErrorOfMonoBehaviours[j])) { return false; } } } if (showErrorIconMissingEventMethod) { if (monoBehaviour.gameObject.activeSelf || showErrorForDisabledComponents) { try { if (isUnityEventsNullOrMissing(monoBehaviour, printError)) { if (!printError) { return true; } } } catch { } } } if (showErrorTypeReferenceIsNull || showErrorTypeStringIsEmpty || showErrorTypeReferenceIsMissing) { if (!monoBehaviour.enabled && !showErrorForDisabledComponents) continue; if (!monoBehaviour.gameObject.activeSelf && !showErrorForDisabledGameObjects) continue; Type type = monoBehaviour.GetType(); while (type != null) { BindingFlags bf = BindingFlags.Instance | BindingFlags.Public; if (!type.FullName.Contains("UnityEngine")) bf |= BindingFlags.NonPublic; FieldInfo[] fieldArray = type.GetFields(bf); for (int j = 0; j < fieldArray.Length; j++) { FieldInfo field = fieldArray[j]; if (System.Attribute.IsDefined(field, typeof(HideInInspector)) || System.Attribute.IsDefined(field, typeof(HierarchyNullableAttribute)) || System.Attribute.IsDefined(field, typeof(NonSerializedAttribute)) || field.IsStatic) continue; if (field.IsPrivate || !field.IsPublic) { if (!Attribute.IsDefined(field, typeof(SerializeField))) { continue; } } object value = field.GetValue(monoBehaviour); try { if (showErrorTypeStringIsEmpty && field.FieldType == typeof(string) && value != null && ((string)value).Equals("")) { if (printError) { appendErrorLine(monoBehaviour.GetType().Name + "." + field.Name + ": String value is empty"); continue; } else { return true; } } } catch { } try { if (showErrorTypeReferenceIsMissing && value != null && value is Component && (Component)value == null) { if (printError) { appendErrorLine(monoBehaviour.GetType().Name + "." + field.Name + ": Reference is missing"); continue; } else { return true; } } } catch { } try { if (showErrorTypeReferenceIsNull && (value == null || value.Equals(null))) { if (printError) { appendErrorLine(monoBehaviour.GetType().Name + "." + field.Name + ": Reference is null"); continue; } else { return true; } } } catch { } try { if (showErrorTypeReferenceIsNull && value != null && (value is IEnumerable)) { foreach (var item in (IEnumerable)value) { if (item == null || item.Equals(null)) { if (printError) { appendErrorLine(monoBehaviour.GetType().Name + "." + field.Name + ": IEnumerable has value with null reference"); continue; } else { return true; } } } } } catch { } } type = type.BaseType; } } } } return false; } private List targetPropertiesNames = new List(10); private bool isUnityEventsNullOrMissing(MonoBehaviour monoBehaviour, bool printError) { targetPropertiesNames.Clear(); FieldInfo[] fieldArray = monoBehaviour.GetType() .GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); for (int i = fieldArray.Length - 1; i >= 0; i--) { FieldInfo field = fieldArray[i]; if (field.FieldType == typeof(UnityEventBase) || field.FieldType.IsSubclassOf(typeof(UnityEventBase))) { targetPropertiesNames.Add(field.Name); } } if (targetPropertiesNames.Count > 0) { SerializedObject serializedMonoBehaviour = new SerializedObject(monoBehaviour); for (int i = targetPropertiesNames.Count - 1; i >= 0; i--) { string targetProperty = targetPropertiesNames[i]; SerializedProperty property = serializedMonoBehaviour.FindProperty(targetProperty); SerializedProperty propertyRelativeArrray = property.FindPropertyRelative("m_PersistentCalls.m_Calls"); for (int j = propertyRelativeArrray.arraySize - 1; j >= 0; j--) { SerializedProperty arrayElementAtIndex = propertyRelativeArrray.GetArrayElementAtIndex(j); SerializedProperty propertyTarget = arrayElementAtIndex.FindPropertyRelative("m_Target"); if (propertyTarget.objectReferenceValue == null) { if (printError) { appendErrorLine(monoBehaviour.GetType().Name + ": Event object reference is null"); } else { return true; } } SerializedProperty propertyMethodName = arrayElementAtIndex.FindPropertyRelative("m_MethodName"); if (string.IsNullOrEmpty(propertyMethodName.stringValue)) { if (printError) { appendErrorLine(monoBehaviour.GetType().Name + ": Event handler function is not selected"); continue; } else { return true; } } string argumentAssemblyTypeName = arrayElementAtIndex.FindPropertyRelative("m_Arguments") .FindPropertyRelative("m_ObjectArgumentAssemblyTypeName").stringValue; System.Type argumentAssemblyType; if (!string.IsNullOrEmpty(argumentAssemblyTypeName)) argumentAssemblyType = System.Type.GetType(argumentAssemblyTypeName, false) ?? typeof(UnityEngine.Object); else argumentAssemblyType = typeof(UnityEngine.Object); UnityEventBase dummyEvent; System.Type propertyTypeName = System.Type.GetType(property.FindPropertyRelative("m_TypeName").stringValue, false); if (propertyTypeName == null) dummyEvent = (UnityEventBase)new UnityEvent(); else dummyEvent = Activator.CreateInstance(propertyTypeName) as UnityEventBase; if (!UnityEventDrawer.IsPersistantListenerValid(dummyEvent, propertyMethodName.stringValue, propertyTarget.objectReferenceValue, (PersistentListenerMode)arrayElementAtIndex.FindPropertyRelative("m_Mode") .enumValueIndex, argumentAssemblyType)) { if (printError) { appendErrorLine(monoBehaviour.GetType().Name + ": Event handler function is missing"); } else { return true; } } } } } return false; } private void appendErrorLine(string error) { errorCount++; errorStringBuilder.Append(errorCount.ToString()); errorStringBuilder.Append(") "); errorStringBuilder.AppendLine(error); } } } ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Component/ErrorComponent.cs.meta ================================================ fileFormatVersion: 2 guid: 7026b875e5a28ee48b737e5d4b7ef24b MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Component/GameObjectIconComponent.cs ================================================ using System; using UnityEngine; using UnityEditor; using VirtueSky.Hierarchy.HComponent.Base; using VirtueSky.Hierarchy; using VirtueSky.Hierarchy.Helper; using VirtueSky.Hierarchy.Data; using System.Reflection; namespace VirtueSky.Hierarchy.HComponent { public class GameObjectIconComponent: BaseComponent { // PRIVATE private MethodInfo getIconMethodInfo; private object[] getIconMethodParams; // CONSTRUCTOR public GameObjectIconComponent () { rect.width = 14; rect.height = 14; getIconMethodInfo = typeof(EditorGUIUtility).GetMethod("GetIconForObject", BindingFlags.NonPublic | BindingFlags.Static ); getIconMethodParams = new object[1]; HierarchySettings.getInstance().addEventListener(HierarchySetting.GameObjectIconShow , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.GameObjectIconShowDuringPlayMode , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.GameObjectIconSize , settingsChanged); settingsChanged(); } // PRIVATE private void settingsChanged() { enabled = HierarchySettings.getInstance().get(HierarchySetting.GameObjectIconShow); showComponentDuringPlayMode = HierarchySettings.getInstance().get(HierarchySetting.GameObjectIconShowDuringPlayMode); HierarchySizeAll size = (HierarchySizeAll)HierarchySettings.getInstance().get(HierarchySetting.GameObjectIconSize); rect.width = rect.height = (size == HierarchySizeAll.Normal ? 15 : (size == HierarchySizeAll.Big ? 16 : 13)); } // DRAW public override LayoutStatus layout(GameObject gameObject, ObjectList objectList, Rect selectionRect, ref Rect curRect, float maxWidth) { if (maxWidth < rect.width + 2) { return LayoutStatus.Failed; } else { curRect.x -= rect.width + 2; rect.x = curRect.x; rect.y = curRect.y - (rect.height - 16) / 2; return LayoutStatus.Success; } } public override void draw(GameObject gameObject, ObjectList objectList, Rect selectionRect) { getIconMethodParams[0] = gameObject; Texture2D icon = (Texture2D)getIconMethodInfo.Invoke(null, getIconMethodParams ); if (icon != null) GUI.DrawTexture(rect, icon, ScaleMode.ScaleToFit, true); } public override void eventHandler(GameObject gameObject, ObjectList objectList, Event currentEvent) { if (currentEvent.isMouse && currentEvent.type == EventType.MouseDown && currentEvent.button == 0 && rect.Contains(currentEvent.mousePosition)) { currentEvent.Use(); Type iconSelectorType = Assembly.Load("UnityEditor").GetType("UnityEditor.IconSelector"); MethodInfo showIconSelectorMethodInfo = iconSelectorType.GetMethod("ShowAtPosition", BindingFlags.Static | BindingFlags.NonPublic); showIconSelectorMethodInfo.Invoke(null, new object[] { gameObject, rect, true }); } } } } ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Component/GameObjectIconComponent.cs.meta ================================================ fileFormatVersion: 2 guid: 1a5637cc504eddd4b960d67f4547b651 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Component/LayerIconComponent.cs ================================================ using System; using System.Collections.Generic; using System.Reflection; using UnityEngine; using UnityEditor; using VirtueSky.Hierarchy.HComponent.Base; using VirtueSky.Hierarchy; using VirtueSky.Hierarchy.Helper; using VirtueSky.Hierarchy.Data; namespace VirtueSky.Hierarchy.HComponent { public class LayerIconComponent: BaseComponent { private List layerTextureList; // CONSTRUCTOR public LayerIconComponent() { rect.width = 14; rect.height = 14; HierarchySettings.getInstance().addEventListener(HierarchySetting.LayerIconShow , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.LayerIconShowDuringPlayMode, settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.LayerIconSize , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.LayerIconList , settingsChanged); settingsChanged(); } // PRIVATE private void settingsChanged() { enabled = HierarchySettings.getInstance().get(HierarchySetting.LayerIconShow); showComponentDuringPlayMode = HierarchySettings.getInstance().get(HierarchySetting.LayerIconShowDuringPlayMode); HierarchySizeAll size = (HierarchySizeAll)HierarchySettings.getInstance().get(HierarchySetting.LayerIconSize); rect.width = rect.height = (size == HierarchySizeAll.Normal ? 15 : (size == HierarchySizeAll.Big ? 16 : 13)); this.layerTextureList = LayerTexture.loadLayerTextureList(); } // DRAW public override LayoutStatus layout(GameObject gameObject, ObjectList objectList, Rect selectionRect, ref Rect curRect, float maxWidth) { if (maxWidth < rect.width) { return LayoutStatus.Failed; } else { curRect.x -= rect.width + 2; rect.x = curRect.x; rect.y = curRect.y - (rect.height - 16) / 2; return LayoutStatus.Success; } } public override void draw(GameObject gameObject, ObjectList objectList, Rect selectionRect) { string gameObjectLayerName = LayerMask.LayerToName(gameObject.layer); LayerTexture layerTexture = layerTextureList.Find(t => t.layer == gameObjectLayerName); if (layerTexture != null && layerTexture.texture != null) { GUI.DrawTexture(rect, layerTexture.texture, ScaleMode.ScaleToFit, true); } } } } ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Component/LayerIconComponent.cs.meta ================================================ fileFormatVersion: 2 guid: 6be765b80f12e6e4c80a42eb744b4df6 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Component/LockComponent.cs ================================================ using System; using System.Collections.Generic; using UnityEngine; using UnityEditor; using VirtueSky.Hierarchy.HComponent.Base; using VirtueSky.Hierarchy; using VirtueSky.Hierarchy.Helper; using VirtueSky.Hierarchy.Data; namespace VirtueSky.Hierarchy.HComponent { public class LockComponent: BaseComponent { // PRIVATE private Color activeColor; private Color inactiveColor; private Texture2D lockButtonTexture; private bool showModifierWarning; private int targetLockState = -1; // CONSTRUCTOR public LockComponent() { rect.width = 13; lockButtonTexture = HierarchyResources.getInstance().getTexture(HierarchyTexture.HierarchyLockButton); HierarchySettings.getInstance().addEventListener(HierarchySetting.AdditionalShowModifierWarning , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.LockShow , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.LockShowDuringPlayMode , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.AdditionalActiveColor , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.AdditionalInactiveColor , settingsChanged); settingsChanged(); } // PRIVATE private void settingsChanged() { showModifierWarning = HierarchySettings.getInstance().get(HierarchySetting.AdditionalShowModifierWarning); enabled = HierarchySettings.getInstance().get(HierarchySetting.LockShow); showComponentDuringPlayMode = HierarchySettings.getInstance().get(HierarchySetting.LockShowDuringPlayMode); activeColor = HierarchySettings.getInstance().getColor(HierarchySetting.AdditionalActiveColor); inactiveColor = HierarchySettings.getInstance().getColor(HierarchySetting.AdditionalInactiveColor); } // DRAW public override LayoutStatus layout(GameObject gameObject, ObjectList objectList, Rect selectionRect, ref Rect curRect, float maxWidth) { if (maxWidth < 13) { return LayoutStatus.Failed; } else { curRect.x -= 13; rect.x = curRect.x; rect.y = curRect.y; return LayoutStatus.Success; } } public override void draw(GameObject gameObject, ObjectList objectList, Rect selectionRect) { bool isLock = isGameObjectLock(gameObject, objectList); if (isLock == true && (gameObject.hideFlags & HideFlags.NotEditable) != HideFlags.NotEditable) { gameObject.hideFlags |= HideFlags.NotEditable; EditorUtility.SetDirty(gameObject); } else if (isLock == false && (gameObject.hideFlags & HideFlags.NotEditable) == HideFlags.NotEditable) { gameObject.hideFlags ^= HideFlags.NotEditable; EditorUtility.SetDirty(gameObject); } HierarchyColorUtils.setColor(isLock ? activeColor : inactiveColor); GUI.DrawTexture(rect, lockButtonTexture); HierarchyColorUtils.clearColor(); } public override void eventHandler(GameObject gameObject, ObjectList objectList, Event currentEvent) { if (currentEvent.isMouse && currentEvent.button == 0 && rect.Contains(currentEvent.mousePosition)) { bool isLock = isGameObjectLock(gameObject, objectList); if (currentEvent.type == EventType.MouseDown) { targetLockState = ((!isLock) == true ? 1 : 0); } else if (currentEvent.type == EventType.MouseDrag && targetLockState != -1) { if (targetLockState == (isLock == true ? 1 : 0)) return; } else { targetLockState = -1; return; } List targetGameObjects = new List(); if (currentEvent.shift) { 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")) { getGameObjectListRecursive(gameObject, ref targetGameObjects); } } else if (currentEvent.alt) { if (gameObject.transform.parent != null) { 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")) { getGameObjectListRecursive(gameObject.transform.parent.gameObject, ref targetGameObjects, 1); targetGameObjects.Remove(gameObject.transform.parent.gameObject); } } else { Debug.Log("This action for root objects is supported only for Unity3d 5.3.3 and above"); return; } } else { if (Selection.Contains(gameObject)) { targetGameObjects.AddRange(Selection.gameObjects); } else { getGameObjectListRecursive(gameObject, ref targetGameObjects, 0); }; } setLock(targetGameObjects, objectList, !isLock); currentEvent.Use(); } } public override void disabledHandler(GameObject gameObject, ObjectList objectList) { if (objectList != null && objectList.lockedObjects.Contains(gameObject)) { objectList.lockedObjects.Remove(gameObject); gameObject.hideFlags &= ~HideFlags.NotEditable; EditorUtility.SetDirty(gameObject); } } // PRIVATE private bool isGameObjectLock(GameObject gameObject, ObjectList objectList) { return objectList == null ? false : objectList.lockedObjects.Contains(gameObject); } private void setLock(List gameObjects, ObjectList objectList, bool targetLock) { if (gameObjects.Count == 0) return; if (objectList == null) objectList = HierarchyObjectListManager.getInstance().getObjectList(gameObjects[0], true); Undo.RecordObject(objectList, targetLock ? "Lock" : "Unlock"); for (int i = gameObjects.Count - 1; i >= 0; i--) { GameObject curGameObject = gameObjects[i]; Undo.RecordObject(curGameObject, targetLock ? "Lock" : "Unlock"); if (targetLock) { curGameObject.hideFlags |= HideFlags.NotEditable; if (!objectList.lockedObjects.Contains(curGameObject)) objectList.lockedObjects.Add(curGameObject); } else { curGameObject.hideFlags &= ~HideFlags.NotEditable; objectList.lockedObjects.Remove(curGameObject); } EditorUtility.SetDirty(curGameObject); } } } } ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Component/LockComponent.cs.meta ================================================ fileFormatVersion: 2 guid: f27ebb809ba98144394f4facad9a7494 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Component/MonoBehaviorIconComponent.cs ================================================ using System; using System.Collections.Generic; using UnityEngine; using UnityEditor; using VirtueSky.Hierarchy.HComponent.Base; using VirtueSky.Hierarchy.Data; using VirtueSky.Hierarchy.Helper; namespace VirtueSky.Hierarchy.HComponent { public class MonoBehaviorIconComponent: BaseComponent { // CONST private const float TREE_STEP_WIDTH = 14.0f; private const float TREE_STEP_HEIGHT = 16.0f; // PRIVATE private Texture2D monoBehaviourIconTexture; private Texture2D monoBehaviourIconObjectTexture; private bool ignoreUnityMonobehaviour; private Color iconColor; private bool showTreeMap; // CONSTRUCTOR public MonoBehaviorIconComponent() { rect.width = 14; rect.height = 16; monoBehaviourIconTexture = HierarchyResources.getInstance().getTexture(HierarchyTexture.HierarchyMonoBehaviourIcon); monoBehaviourIconObjectTexture = HierarchyResources.getInstance().getTexture(HierarchyTexture.HierarchyTreeMapObject); HierarchySettings.getInstance().addEventListener(HierarchySetting.MonoBehaviourIconIgnoreUnityMonobehaviour , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.MonoBehaviourIconShow , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.MonoBehaviourIconShowDuringPlayMode , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.MonoBehaviourIconColor , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.TreeMapShow , settingsChanged); settingsChanged(); } // PRIVATE private void settingsChanged() { ignoreUnityMonobehaviour = HierarchySettings.getInstance().get(HierarchySetting.MonoBehaviourIconIgnoreUnityMonobehaviour); enabled = HierarchySettings.getInstance().get(HierarchySetting.MonoBehaviourIconShow); showComponentDuringPlayMode = HierarchySettings.getInstance().get(HierarchySetting.MonoBehaviourIconShowDuringPlayMode); iconColor = HierarchySettings.getInstance().getColor(HierarchySetting.MonoBehaviourIconColor); showTreeMap = HierarchySettings.getInstance().get(HierarchySetting.TreeMapShow); EditorApplication.RepaintHierarchyWindow(); } public override void draw(GameObject gameObject, ObjectList objectList, Rect selectionRect) { bool foundCustomComponent = false; if (ignoreUnityMonobehaviour) { Component[] components = gameObject.GetComponents(); for (int i = components.Length - 1; i >= 0; i--) { if (components[i] != null && !components[i].GetType().FullName.Contains("UnityEngine")) { foundCustomComponent = true; break; } } } else { foundCustomComponent = gameObject.GetComponent() != null; } if (foundCustomComponent) { int ident = Mathf.FloorToInt(selectionRect.x / TREE_STEP_WIDTH) - 1; rect.x = ident * TREE_STEP_WIDTH; rect.y = selectionRect.y; rect.width = 16; #if UNITY_2018_3_OR_NEWER rect.x += TREE_STEP_WIDTH + 1; rect.width += 1; #elif UNITY_5_6_OR_NEWER #elif UNITY_5_3_OR_NEWER rect.x += TREE_STEP_WIDTH; #endif HierarchyColorUtils.setColor(iconColor); GUI.DrawTexture(rect, monoBehaviourIconTexture); HierarchyColorUtils.clearColor(); if (!showTreeMap && gameObject.transform.childCount == 0) { rect.width = 14; GUI.DrawTexture(rect, monoBehaviourIconObjectTexture); } } } } } ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Component/MonoBehaviorIconComponent.cs.meta ================================================ fileFormatVersion: 2 guid: a698db12abba706458883608fe26624b MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Component/PrefabComponent.cs ================================================ using System; using System.Collections.Generic; using UnityEngine; using UnityEditor; using VirtueSky.Hierarchy.HComponent.Base; using VirtueSky.Hierarchy.Data; using VirtueSky.Hierarchy.Helper; namespace VirtueSky.Hierarchy.HComponent { public class PrefabComponent: BaseComponent { // PRIVATE private Color activeColor; private Color inactiveColor; private Texture2D prefabTexture; private bool showPrefabConnectedIcon; // CONSTRUCTOR public PrefabComponent() { rect.width = 9; prefabTexture = HierarchyResources.getInstance().getTexture(HierarchyTexture.HierarchyPrefabIcon); HierarchySettings.getInstance().addEventListener(HierarchySetting.PrefabShowBreakedPrefabsOnly , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.PrefabShow , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.AdditionalActiveColor , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.AdditionalInactiveColor , settingsChanged); settingsChanged(); } // PRIVATE private void settingsChanged() { showPrefabConnectedIcon = HierarchySettings.getInstance().get(HierarchySetting.PrefabShowBreakedPrefabsOnly); enabled = HierarchySettings.getInstance().get(HierarchySetting.PrefabShow); activeColor = HierarchySettings.getInstance().getColor(HierarchySetting.AdditionalActiveColor); inactiveColor = HierarchySettings.getInstance().getColor(HierarchySetting.AdditionalInactiveColor); } // DRAW public override LayoutStatus layout(GameObject gameObject, ObjectList objectList, Rect selectionRect, ref Rect curRect, float maxWidth) { if (maxWidth < 9) { return LayoutStatus.Failed; } else { curRect.x -= 9; rect.x = curRect.x; rect.y = curRect.y; return LayoutStatus.Success; } } public override void draw(GameObject gameObject, ObjectList objectList, Rect selectionRect) { #if UNITY_2018_3_OR_NEWER PrefabInstanceStatus prefabStatus = PrefabUtility.GetPrefabInstanceStatus(gameObject); if (prefabStatus == PrefabInstanceStatus.MissingAsset || prefabStatus == PrefabInstanceStatus.Disconnected) { HierarchyColorUtils.setColor(inactiveColor); GUI.DrawTexture(rect, prefabTexture); HierarchyColorUtils.clearColor(); } else if (!showPrefabConnectedIcon && prefabStatus != PrefabInstanceStatus.NotAPrefab) { HierarchyColorUtils.setColor(activeColor); GUI.DrawTexture(rect, prefabTexture); HierarchyColorUtils.clearColor(); } #else PrefabType prefabType = PrefabUtility.GetPrefabType(gameObject); if (prefabType == PrefabType.MissingPrefabInstance || prefabType == PrefabType.DisconnectedPrefabInstance || prefabType == PrefabType.DisconnectedModelPrefabInstance) { QColorUtils.setColor(inactiveColor); GUI.DrawTexture(rect, prefabTexture); QColorUtils.clearColor(); } else if (!showPrefabConnectedIcon && prefabType != PrefabType.None) { QColorUtils.setColor(activeColor); GUI.DrawTexture(rect, prefabTexture); QColorUtils.clearColor(); } #endif } } } ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Component/PrefabComponent.cs.meta ================================================ fileFormatVersion: 2 guid: 8122ed3c57f6b3847a0daefdae539039 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Component/RendererComponent.cs ================================================ using System; using System.Collections.Generic; using UnityEngine; using UnityEditor; using VirtueSky.Hierarchy.HComponent.Base; using VirtueSky.Hierarchy; using VirtueSky.Hierarchy.Data; using VirtueSky.Hierarchy.Helper; namespace VirtueSky.Hierarchy.HComponent { public class RendererComponent: BaseComponent { // PRIVATE private Color activeColor; private Color inactiveColor; private Color specialColor; private Texture2D rendererButtonTexture; private int targetRendererMode = -1; // CONSTRUCTOR public RendererComponent() { rect.width = 12; rendererButtonTexture = HierarchyResources.getInstance().getTexture(HierarchyTexture.HierarchyRendererButton); HierarchySettings.getInstance().addEventListener(HierarchySetting.RendererShow , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.RendererShowDuringPlayMode, settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.AdditionalActiveColor , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.AdditionalInactiveColor , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.AdditionalSpecialColor , settingsChanged); settingsChanged(); } // PRIVATE private void settingsChanged() { enabled = HierarchySettings.getInstance().get(HierarchySetting.RendererShow); showComponentDuringPlayMode = HierarchySettings.getInstance().get(HierarchySetting.RendererShowDuringPlayMode); activeColor = HierarchySettings.getInstance().getColor(HierarchySetting.AdditionalActiveColor); inactiveColor = HierarchySettings.getInstance().getColor(HierarchySetting.AdditionalInactiveColor); specialColor = HierarchySettings.getInstance().getColor(HierarchySetting.AdditionalSpecialColor); } // DRAW public override LayoutStatus layout(GameObject gameObject, ObjectList objectList, Rect selectionRect, ref Rect curRect, float maxWidth) { if (maxWidth < 12) { return LayoutStatus.Failed; } else { curRect.x -= 12; rect.x = curRect.x; rect.y = curRect.y; return LayoutStatus.Success; } } public override void disabledHandler(GameObject gameObject, ObjectList objectList) { if (objectList != null && objectList.wireframeHiddenObjects.Contains(gameObject)) { objectList.wireframeHiddenObjects.Remove(gameObject); Renderer renderer = gameObject.GetComponent(); if (renderer != null) setSelectedRenderState(renderer, false); } } public override void draw(GameObject gameObject, ObjectList objectList, Rect selectionRect) { Renderer renderer = gameObject.GetComponent(); if (renderer != null) { bool wireframeHiddenObjectsContains = isWireframeHidden(gameObject, objectList); if (wireframeHiddenObjectsContains) { HierarchyColorUtils.setColor(specialColor); GUI.DrawTexture(rect, rendererButtonTexture); HierarchyColorUtils.clearColor(); } else if (renderer.enabled) { HierarchyColorUtils.setColor(activeColor); GUI.DrawTexture(rect, rendererButtonTexture); HierarchyColorUtils.clearColor(); } else { HierarchyColorUtils.setColor(inactiveColor); GUI.DrawTexture(rect, rendererButtonTexture); HierarchyColorUtils.clearColor(); } } } public override void eventHandler(GameObject gameObject, ObjectList objectList, Event currentEvent) { if (currentEvent.isMouse && currentEvent.button == 0 && rect.Contains(currentEvent.mousePosition)) { Renderer renderer = gameObject.GetComponent(); if (renderer != null) { bool wireframeHiddenObjectsContains = isWireframeHidden(gameObject, objectList); bool isEnabled = renderer.enabled; if (currentEvent.type == EventType.MouseDown) { targetRendererMode = ((!isEnabled) == true ? 1 : 0); } else if (currentEvent.type == EventType.MouseDrag && targetRendererMode != -1) { if (targetRendererMode == (isEnabled == true ? 1 : 0)) return; } else { targetRendererMode = -1; return; } Undo.RecordObject(renderer, "renderer visibility change"); if (currentEvent.control || currentEvent.command) { if (!wireframeHiddenObjectsContains) { setSelectedRenderState(renderer, true); SceneView.RepaintAll(); setWireframeMode(gameObject, objectList, true); } } else { if (wireframeHiddenObjectsContains) { setSelectedRenderState(renderer, false); SceneView.RepaintAll(); setWireframeMode(gameObject, objectList, false); } else { Undo.RecordObject(renderer, isEnabled ? "Disable Component" : "Enable Component"); renderer.enabled = !isEnabled; } } EditorUtility.SetDirty(gameObject); } currentEvent.Use(); } } // PRIVATE public bool isWireframeHidden(GameObject gameObject, ObjectList objectList) { return objectList == null ? false : objectList.wireframeHiddenObjects.Contains(gameObject); } public void setWireframeMode(GameObject gameObject, ObjectList objectList, bool targetWireframe) { if (objectList == null && targetWireframe) objectList = HierarchyObjectListManager.getInstance().getObjectList(gameObject, true); if (objectList != null) { Undo.RecordObject(objectList, "Renderer Visibility Change"); if (targetWireframe) objectList.wireframeHiddenObjects.Add(gameObject); else objectList.wireframeHiddenObjects.Remove(gameObject); EditorUtility.SetDirty(objectList); } } static public void setSelectedRenderState(Renderer renderer, bool visible) { #if UNITY_5_5_OR_NEWER EditorUtility.SetSelectedRenderState(renderer, visible ? EditorSelectedRenderState.Wireframe : EditorSelectedRenderState.Hidden); #else EditorUtility.SetSelectedWireframeHidden(renderer, visible); #endif } } } ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Component/RendererComponent.cs.meta ================================================ fileFormatVersion: 2 guid: cff04b7651ffbf546aa976ab3f1203ec MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Component/SeparatorComponent.cs ================================================ using System; using System.Collections.Generic; using UnityEngine; using UnityEditor; using VirtueSky.Hierarchy.HComponent.Base; using VirtueSky.Hierarchy.Data; using VirtueSky.Hierarchy.Helper; namespace VirtueSky.Hierarchy.HComponent { public class SeparatorComponent: BaseComponent { // PRIVATE private Color separatorColor; private Color evenShadingColor; private Color oddShadingColor; private bool showRowShading; // CONSTRUCTOR public SeparatorComponent () { showComponentDuringPlayMode = true; HierarchySettings.getInstance().addEventListener(HierarchySetting.SeparatorShowRowShading , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.SeparatorShow , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.SeparatorColor , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.SeparatorEvenRowShadingColor , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.SeparatorOddRowShadingColor , settingsChanged); settingsChanged(); } // PRIVATE private void settingsChanged() { showRowShading = HierarchySettings.getInstance().get(HierarchySetting.SeparatorShowRowShading); enabled = HierarchySettings.getInstance().get(HierarchySetting.SeparatorShow); evenShadingColor = HierarchySettings.getInstance().getColor(HierarchySetting.SeparatorEvenRowShadingColor); oddShadingColor = HierarchySettings.getInstance().getColor(HierarchySetting.SeparatorOddRowShadingColor); separatorColor = HierarchySettings.getInstance().getColor(HierarchySetting.SeparatorColor); } // DRAW public override void draw(GameObject gameObject, ObjectList objectList, Rect selectionRect) { rect.y = selectionRect.y; rect.width = selectionRect.width + selectionRect.x; rect.height = 1; rect.x = 0; EditorGUI.DrawRect(rect, separatorColor); if (showRowShading) { selectionRect.width += selectionRect.x; selectionRect.x = 0; selectionRect.height -=1; selectionRect.y += 1; EditorGUI.DrawRect(selectionRect, ((Mathf.FloorToInt(((selectionRect.y - 4) / 16) % 2) == 0)) ? evenShadingColor : oddShadingColor); } } } } ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Component/SeparatorComponent.cs.meta ================================================ fileFormatVersion: 2 guid: 86f5d0dd87df7d441a321be0035d2871 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Component/StaticComponent.cs ================================================ using System; using System.Collections.Generic; using UnityEngine; using UnityEditor; using VirtueSky.Hierarchy.HComponent.Base; using VirtueSky.Hierarchy.Data; using VirtueSky.Hierarchy; using VirtueSky.Hierarchy.Helper; namespace VirtueSky.Hierarchy.HComponent { public class StaticComponent: BaseComponent { // PRIVATE private Color activeColor; private Color inactiveColor; private StaticEditorFlags staticFlags; private GameObject[] gameObjects; private Texture2D staticButton; private Color32[] staticButtonColors; // CONSTRUCTOR public StaticComponent() { rect.width = 11; rect.height = 10; HierarchySettings.getInstance().addEventListener(HierarchySetting.StaticShow , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.StaticShowDuringPlayMode , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.AdditionalActiveColor , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.AdditionalInactiveColor , settingsChanged); settingsChanged(); } // PRIVATE private void settingsChanged() { enabled = HierarchySettings.getInstance().get(HierarchySetting.StaticShow); showComponentDuringPlayMode = HierarchySettings.getInstance().get(HierarchySetting.StaticShowDuringPlayMode); activeColor = HierarchySettings.getInstance().getColor(HierarchySetting.AdditionalActiveColor); inactiveColor = HierarchySettings.getInstance().getColor(HierarchySetting.AdditionalInactiveColor); } // DRAW public override LayoutStatus layout(GameObject gameObject, ObjectList objectList, Rect selectionRect, ref Rect curRect, float maxWidth) { if (maxWidth < 13) { return LayoutStatus.Failed; } else { curRect.x -= 13; rect.x = curRect.x; rect.y = curRect.y + 4; staticFlags = GameObjectUtility.GetStaticEditorFlags(gameObject); return LayoutStatus.Success; } } public override void draw(GameObject gameObject, ObjectList objectList, Rect selectionRect) { if (staticButton == null) { staticButton = new Texture2D(11, 10, TextureFormat.ARGB32, false, true); staticButtonColors = new Color32[11 * 10]; } #if UNITY_4_6 || UNITY_4_7 drawQuad(39, 5, 4, ((staticFlags & StaticEditorFlags.LightmapStatic ) > 0)); drawQuad(33, 5, 4, ((staticFlags & StaticEditorFlags.BatchingStatic ) > 0)); #else drawQuad(37, 3, 4, ((staticFlags & StaticEditorFlags.ContributeGI ) > 0)); drawQuad(33, 3, 4, ((staticFlags & StaticEditorFlags.BatchingStatic ) > 0)); drawQuad(41, 3, 4, ((staticFlags & StaticEditorFlags.ReflectionProbeStatic) > 0)); #endif drawQuad( 0, 5, 2, ((staticFlags & StaticEditorFlags.OccludeeStatic ) > 0)); drawQuad( 6, 5, 2, ((staticFlags & StaticEditorFlags.OccluderStatic ) > 0)); drawQuad(88, 5, 2, ((staticFlags & StaticEditorFlags.NavigationStatic ) > 0)); drawQuad(94, 5, 2, ((staticFlags & StaticEditorFlags.OffMeshLinkGeneration) > 0)); staticButton.SetPixels32(staticButtonColors); staticButton.Apply(); GUI.DrawTexture(rect, staticButton); } public override void eventHandler(GameObject gameObject, ObjectList objectList, Event currentEvent) { if (currentEvent.isMouse && currentEvent.type == EventType.MouseDown && currentEvent.button == 0 && rect.Contains(currentEvent.mousePosition)) { currentEvent.Use(); int intStaticFlags = (int)staticFlags; gameObjects = Selection.Contains(gameObject) ? Selection.gameObjects : new GameObject[] { gameObject }; GenericMenu menu = new GenericMenu(); menu.AddItem(new GUIContent("Nothing" ), intStaticFlags == 0, staticChangeHandler, 0); menu.AddItem(new GUIContent("Everything" ), intStaticFlags == -1, staticChangeHandler, -1); menu.AddItem(new GUIContent("Lightmap Static" ), (intStaticFlags & (int)StaticEditorFlags.ContributeGI) > 0, staticChangeHandler, (int)StaticEditorFlags.ContributeGI); menu.AddItem(new GUIContent("Occluder Static" ), (intStaticFlags & (int)StaticEditorFlags.OccluderStatic) > 0, staticChangeHandler, (int)StaticEditorFlags.OccluderStatic); menu.AddItem(new GUIContent("Batching Static" ), (intStaticFlags & (int)StaticEditorFlags.BatchingStatic) > 0, staticChangeHandler, (int)StaticEditorFlags.BatchingStatic); menu.AddItem(new GUIContent("Navigation Static" ), (intStaticFlags & (int)StaticEditorFlags.NavigationStatic) > 0, staticChangeHandler, (int)StaticEditorFlags.NavigationStatic); menu.AddItem(new GUIContent("Occludee Static" ), (intStaticFlags & (int)StaticEditorFlags.OccludeeStatic) > 0, staticChangeHandler, (int)StaticEditorFlags.OccludeeStatic); menu.AddItem(new GUIContent("Off Mesh Link Generation" ), (intStaticFlags & (int)StaticEditorFlags.OffMeshLinkGeneration) > 0, staticChangeHandler, (int)StaticEditorFlags.OffMeshLinkGeneration); #if UNITY_4_6 || UNITY_4_7 #else menu.AddItem(new GUIContent("Reflection Probe Static" ), (intStaticFlags & (int)StaticEditorFlags.ReflectionProbeStatic) > 0, staticChangeHandler, (int)StaticEditorFlags.ReflectionProbeStatic); #endif menu.ShowAsContext(); } } // PRIVATE private void staticChangeHandler(object result) { int intResult = (int)result; StaticEditorFlags resultStaticFlags = (StaticEditorFlags)result; if (intResult != 0 && intResult != -1) { resultStaticFlags = staticFlags ^ resultStaticFlags; } for (int i = gameObjects.Length - 1; i >= 0; i--) { GameObject gameObject = gameObjects[i]; Undo.RecordObject(gameObject, "Change Static Flags"); GameObjectUtility.SetStaticEditorFlags(gameObject, resultStaticFlags); EditorUtility.SetDirty(gameObject); } } private void drawQuad(int startPosition, int width, int height, bool isActiveColor) { Color32 color = isActiveColor ? activeColor : inactiveColor; for (int iy = 0; iy < height; iy++) { for (int ix = 0; ix < width; ix++) { int pos = startPosition + ix + iy * 11; staticButtonColors[pos].r = color.r; staticButtonColors[pos].g = color.g; staticButtonColors[pos].b = color.b; staticButtonColors[pos].a = color.a; } } } } } ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Component/StaticComponent.cs.meta ================================================ fileFormatVersion: 2 guid: bad9267f99b998b42adf5da1f9f75760 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Component/TagIconComponent.cs ================================================ using System; using System.Collections.Generic; using System.Reflection; using UnityEngine; using UnityEditor; using VirtueSky.Hierarchy.HComponent.Base; using VirtueSky.Hierarchy; using VirtueSky.Hierarchy.Helper; using VirtueSky.Hierarchy.Data; namespace VirtueSky.Hierarchy.HComponent { public class TagIconComponent: BaseComponent { private List tagTextureList; // CONSTRUCTOR public TagIconComponent() { rect.width = 14; rect.height = 14; HierarchySettings.getInstance().addEventListener(HierarchySetting.TagIconShow , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.TagIconShowDuringPlayMode, settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.TagIconSize , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.TagIconList , settingsChanged); settingsChanged(); } // PRIVATE private void settingsChanged() { enabled = HierarchySettings.getInstance().get(HierarchySetting.TagIconShow); showComponentDuringPlayMode = HierarchySettings.getInstance().get(HierarchySetting.TagIconShowDuringPlayMode); HierarchySizeAll size = (HierarchySizeAll)HierarchySettings.getInstance().get(HierarchySetting.TagIconSize); rect.width = rect.height = (size == HierarchySizeAll.Normal ? 15 : (size == HierarchySizeAll.Big ? 16 : 13)); this.tagTextureList = TagTexture.loadTagTextureList(); } // DRAW public override LayoutStatus layout(GameObject gameObject, ObjectList objectList, Rect selectionRect, ref Rect curRect, float maxWidth) { if (maxWidth < rect.width) { return LayoutStatus.Failed; } else { curRect.x -= rect.width + 2; rect.x = curRect.x; rect.y = curRect.y - (rect.height - 16) / 2; return LayoutStatus.Success; } } public override void draw(GameObject gameObject, ObjectList objectList, Rect selectionRect) { string gameObjectTag = ""; try { gameObjectTag = gameObject.tag; } catch {} TagTexture tagTexture = tagTextureList.Find(t => t.tag == gameObjectTag); if (tagTexture != null && tagTexture.texture != null) { GUI.DrawTexture(rect, tagTexture.texture, ScaleMode.ScaleToFit, true); } } } } ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Component/TagIconComponent.cs.meta ================================================ fileFormatVersion: 2 guid: 53c992a7ba1ab9747a352e958d4850b6 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Component/TagLayerComponent.cs ================================================ using System; using System.Collections.Generic; using UnityEngine; using UnityEditor; using VirtueSky.Hierarchy.HComponent.Base; using VirtueSky.Hierarchy.Data; using System.Reflection; namespace VirtueSky.Hierarchy.HComponent { public class TagLayerComponent: BaseComponent { // PRIVATE private GUIStyle labelStyle; private HierarchyTagAndLayerShowType showType; private Color layerColor; private Color tagColor; private bool showAlways; private bool sizeIsPixel; private int pixelSize; private float percentSize; private GameObject[] gameObjects; private float labelAlpha; private HierarchyTagAndLayerLabelSize labelSize; private Rect tagRect = new Rect(); private Rect layerRect = new Rect(); private bool needDrawTag; private bool needDrawLayer; private int layer; private string tag; // CONSTRUCTOR public TagLayerComponent() { labelStyle = new GUIStyle(); labelStyle.fontSize = 8; labelStyle.clipping = TextClipping.Clip; labelStyle.alignment = TextAnchor.MiddleLeft; HierarchySettings.getInstance().addEventListener(HierarchySetting.TagAndLayerSizeShowType , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.TagAndLayerType , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.TagAndLayerSizeValueType , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.TagAndLayerSizeValuePixel , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.TagAndLayerSizeValuePercent , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.TagAndLayerLabelSize , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.TagAndLayerShow , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.TagAndLayerShowDuringPlayMode , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.TagAndLayerTagLabelColor , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.TagAndLayerLayerLabelColor , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.TagAndLayerAligment , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.TagAndLayerLabelAlpha , settingsChanged); settingsChanged(); } // PRIVATE private void settingsChanged() { showAlways = HierarchySettings.getInstance().get(HierarchySetting.TagAndLayerType) == (int)HierarchyTagAndLayerType.Always; showType = (HierarchyTagAndLayerShowType)HierarchySettings.getInstance().get(HierarchySetting.TagAndLayerSizeShowType); sizeIsPixel = HierarchySettings.getInstance().get(HierarchySetting.TagAndLayerSizeValueType) == (int)HierarchyTagAndLayerSizeType.Pixel; pixelSize = HierarchySettings.getInstance().get(HierarchySetting.TagAndLayerSizeValuePixel); percentSize = HierarchySettings.getInstance().get(HierarchySetting.TagAndLayerSizeValuePercent); labelSize = (HierarchyTagAndLayerLabelSize)HierarchySettings.getInstance().get(HierarchySetting.TagAndLayerLabelSize); enabled = HierarchySettings.getInstance().get(HierarchySetting.TagAndLayerShow); tagColor = HierarchySettings.getInstance().getColor(HierarchySetting.TagAndLayerTagLabelColor); layerColor = HierarchySettings.getInstance().getColor(HierarchySetting.TagAndLayerLayerLabelColor); labelAlpha = HierarchySettings.getInstance().get(HierarchySetting.TagAndLayerLabelAlpha); showComponentDuringPlayMode = HierarchySettings.getInstance().get(HierarchySetting.TagAndLayerShowDuringPlayMode); HierarchyTagAndLayerAligment aligment = (HierarchyTagAndLayerAligment)HierarchySettings.getInstance().get(HierarchySetting.TagAndLayerAligment); switch (aligment) { case HierarchyTagAndLayerAligment.Left : labelStyle.alignment = TextAnchor.MiddleLeft; break; case HierarchyTagAndLayerAligment.Center: labelStyle.alignment = TextAnchor.MiddleCenter; break; case HierarchyTagAndLayerAligment.Right : labelStyle.alignment = TextAnchor.MiddleRight; break; } } // DRAW public override LayoutStatus layout(GameObject gameObject, ObjectList objectList, Rect selectionRect, ref Rect curRect, float maxWidth) { float textWidth = sizeIsPixel ? pixelSize : percentSize * rect.x; rect.width = textWidth + 4; if (maxWidth < rect.width) { return LayoutStatus.Failed; } else { curRect.x -= rect.width + 2; rect.x = curRect.x; rect.y = curRect.y; rect.y += (EditorGUIUtility.singleLineHeight - rect.height) * 0.5f; //rect.height = EditorGUIUtility.singleLineHeight; layer = gameObject.layer; tag = getTagName(gameObject); needDrawTag = (showType != HierarchyTagAndLayerShowType.Layer) && ((showAlways || tag != "Untagged")); needDrawLayer = (showType != HierarchyTagAndLayerShowType.Tag ) && ((showAlways || layer != 0 )); #if UNITY_2019_1_OR_NEWER if (labelSize == HierarchyTagAndLayerLabelSize.Big || (labelSize == HierarchyTagAndLayerLabelSize.BigIfSpecifiedOnlyTagOrLayer && needDrawTag != needDrawLayer)) labelStyle.fontSize = 8; else labelStyle.fontSize = 7; #else if (labelSize == QHierarchyTagAndLayerLabelSize.Big || (labelSize == QHierarchyTagAndLayerLabelSize.BigIfSpecifiedOnlyTagOrLayer && needDrawTag != needDrawLayer)) labelStyle.fontSize = 9; else labelStyle.fontSize = 8; #endif if (needDrawTag) tagRect.Set(rect.x, rect.y - (needDrawLayer ? 4 : 0), rect.width, rect.height); if (needDrawLayer) layerRect.Set(rect.x, rect.y + (needDrawTag ? 4 : 0), rect.width, rect.height); return LayoutStatus.Success; } } public override void draw(GameObject gameObject, ObjectList objectList, Rect selectionRect) { if (needDrawTag ) { tagColor.a = (tag == "Untagged" ? labelAlpha : 1.0f); labelStyle.normal.textColor = tagColor; EditorGUI.LabelField(tagRect, tag, labelStyle); } if (needDrawLayer) { layerColor.a = (layer == 0 ? labelAlpha : 1.0f); labelStyle.normal.textColor = layerColor; EditorGUI.LabelField(layerRect, getLayerName(layer), labelStyle); } } public override void eventHandler(GameObject gameObject, ObjectList objectList, Event currentEvent) { if (Event.current.isMouse && currentEvent.type == EventType.MouseDown && Event.current.button == 0) { if (needDrawTag && needDrawLayer) { tagRect.height = 8; layerRect.height = 8; tagRect.y += 4; layerRect.y += 4; } if (needDrawTag && tagRect.Contains(Event.current.mousePosition)) { gameObjects = Selection.Contains(gameObject) ? Selection.gameObjects : new GameObject[] { gameObject }; showTagsContextMenu(tag); Event.current.Use(); } else if (needDrawLayer && layerRect.Contains(Event.current.mousePosition)) { gameObjects = Selection.Contains(gameObject) ? Selection.gameObjects : new GameObject[] { gameObject }; showLayersContextMenu(LayerMask.LayerToName(layer)); Event.current.Use(); } } } private string getTagName(GameObject gameObject) { string tag = "Undefined"; try { tag = gameObject.tag; } catch {} return tag; } public string getLayerName(int layer) { string layerName = LayerMask.LayerToName(layer); if (layerName.Equals("")) layerName = "Undefined"; return layerName; } // PRIVATE private void showTagsContextMenu(string tag) { List tags = new List(UnityEditorInternal.InternalEditorUtility.tags); GenericMenu menu = new GenericMenu(); menu.AddItem(new GUIContent("Untagged" ), false, tagChangedHandler, "Untagged"); for (int i = 0, n = tags.Count; i < n; i++) { string curTag = tags[i]; menu.AddItem(new GUIContent(curTag), tag == curTag, tagChangedHandler, curTag); } menu.AddSeparator(""); menu.AddItem(new GUIContent("Add Tag..." ), false, addTagOrLayerHandler, "Tags"); menu.ShowAsContext(); } private void showLayersContextMenu(string layer) { List layers = new List(UnityEditorInternal.InternalEditorUtility.layers); GenericMenu menu = new GenericMenu(); menu.AddItem(new GUIContent("Default" ), false, layerChangedHandler, "Default"); for (int i = 0, n = layers.Count; i < n; i++) { string curLayer = layers[i]; menu.AddItem(new GUIContent(curLayer), layer == curLayer, layerChangedHandler, curLayer); } menu.AddSeparator(""); menu.AddItem(new GUIContent("Add Layer..." ), false, addTagOrLayerHandler, "Layers"); menu.ShowAsContext(); } private void tagChangedHandler(object newTag) { for (int i = gameObjects.Length - 1; i >= 0; i--) { GameObject gameObject = gameObjects[i]; Undo.RecordObject(gameObject, "Change Tag"); gameObject.tag = (string)newTag; EditorUtility.SetDirty(gameObject); } } private void layerChangedHandler(object newLayer) { int newLayerId = LayerMask.NameToLayer((string)newLayer); for (int i = gameObjects.Length - 1; i >= 0; i--) { GameObject gameObject = gameObjects[i]; Undo.RecordObject(gameObject, "Change Layer"); gameObject.layer = newLayerId; EditorUtility.SetDirty(gameObject); } } private void addTagOrLayerHandler(object value) { PropertyInfo propertyInfo = typeof(EditorApplication).GetProperty("tagManager", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.GetProperty); UnityEngine.Object obj = (UnityEngine.Object)(propertyInfo.GetValue(null, null)); obj.GetType().GetField("m_DefaultExpandedFoldout").SetValue(obj, value); Selection.activeObject = obj; } } } ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Component/TagLayerComponent.cs.meta ================================================ fileFormatVersion: 2 guid: cde42cc8a02faf544ad81c7744878785 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Component/TreeMapComponent.cs ================================================ using UnityEngine; using UnityEditor; using System; using VirtueSky.Hierarchy.HComponent.Base; using VirtueSky.Hierarchy.Data; using VirtueSky.Hierarchy; using VirtueSky.Hierarchy.Helper; using System.Collections.Generic; using System.Collections; namespace VirtueSky.Hierarchy.HComponent { public class TreeMapComponent: BaseComponent { // CONST private const float TREE_STEP_WIDTH = 14.0f; // PRIVATE private Texture2D treeMapLevelTexture; private Texture2D treeMapLevel4Texture; private Texture2D treeMapCurrentTexture; private Texture2D treeMapLastTexture; private Texture2D treeMapObjectTexture; private bool enhanced; private bool transparentBackground; private Color backgroundColor; private Color treeMapColor; // CONSTRUCTOR public TreeMapComponent() { treeMapLevelTexture = HierarchyResources.getInstance().getTexture(HierarchyTexture.HierarchyTreeMapLevel); treeMapLevel4Texture = HierarchyResources.getInstance().getTexture(HierarchyTexture.HierarchyTreeMapLevel4); treeMapCurrentTexture = HierarchyResources.getInstance().getTexture(HierarchyTexture.HierarchyTreeMapCurrent); #if UNITY_2018_3_OR_NEWER treeMapObjectTexture = HierarchyResources.getInstance().getTexture(HierarchyTexture.HierarchyTreeMapLine); #else treeMapObjectTexture = QResources.getInstance().getTexture(QTexture.QTreeMapObject); #endif treeMapLastTexture = HierarchyResources.getInstance().getTexture(HierarchyTexture.HierarchyTreeMapLast); rect.width = 14; rect.height = 16; showComponentDuringPlayMode = true; HierarchySettings.getInstance().addEventListener(HierarchySetting.AdditionalBackgroundColor, settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.TreeMapShow , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.TreeMapColor , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.TreeMapEnhanced , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.TreeMapTransparentBackground, settingsChanged); settingsChanged(); } // PRIVATE private void settingsChanged() { backgroundColor = HierarchySettings.getInstance().getColor(HierarchySetting.AdditionalBackgroundColor); enabled = HierarchySettings.getInstance().get(HierarchySetting.TreeMapShow); treeMapColor = HierarchySettings.getInstance().getColor(HierarchySetting.TreeMapColor); enhanced = HierarchySettings.getInstance().get(HierarchySetting.TreeMapEnhanced); transparentBackground = HierarchySettings.getInstance().get(HierarchySetting.TreeMapTransparentBackground); } // DRAW public override LayoutStatus layout(GameObject gameObject, ObjectList objectList, Rect selectionRect, ref Rect curRect, float maxWidth) { rect.y = selectionRect.y; if (!transparentBackground) { rect.x = 0; rect.width = selectionRect.x - 14; EditorGUI.DrawRect(rect, backgroundColor); rect.width = 14; } return LayoutStatus.Success; } public override void draw(GameObject gameObject, ObjectList objectList, Rect selectionRect) { int childCount = gameObject.transform.childCount; int level = Mathf.RoundToInt(selectionRect.x / 14.0f); if (enhanced) { Transform gameObjectTransform = gameObject.transform; Transform parentTransform = null; for (int i = 0, j = level - 1; j >= 0; i++, j--) { rect.x = 14 * j; if (i == 0) { if (childCount == 0) { #if UNITY_2018_3_OR_NEWER HierarchyColorUtils.setColor(treeMapColor); #endif GUI.DrawTexture(rect, treeMapObjectTexture); } gameObjectTransform = gameObject.transform; } else if (i == 1) { HierarchyColorUtils.setColor(treeMapColor); if (parentTransform == null) { if (gameObjectTransform.GetSiblingIndex() == gameObject.scene.rootCount - 1) { GUI.DrawTexture(rect, treeMapLastTexture); } else { GUI.DrawTexture(rect, treeMapCurrentTexture); } } else if (gameObjectTransform.GetSiblingIndex() == parentTransform.childCount - 1) { GUI.DrawTexture(rect, treeMapLastTexture); } else { GUI.DrawTexture(rect, treeMapCurrentTexture); } gameObjectTransform = parentTransform; } else { if (parentTransform == null) { if (gameObjectTransform.GetSiblingIndex() != gameObject.scene.rootCount - 1) GUI.DrawTexture(rect, treeMapLevelTexture); } else if (gameObjectTransform.GetSiblingIndex() != parentTransform.childCount - 1) GUI.DrawTexture(rect, treeMapLevelTexture); gameObjectTransform = parentTransform; } if (gameObjectTransform != null) parentTransform = gameObjectTransform.parent; else break; } HierarchyColorUtils.clearColor(); } else { for (int i = 0, j = level - 1; j >= 0; i++, j--) { rect.x = 14 * j; if (i == 0) { if (childCount > 0) continue; else { #if UNITY_2018_3_OR_NEWER HierarchyColorUtils.setColor(treeMapColor); #endif GUI.DrawTexture(rect, treeMapObjectTexture); } } else if (i == 1) { HierarchyColorUtils.setColor(treeMapColor); GUI.DrawTexture(rect, treeMapCurrentTexture); } else { rect.width = 14 * 4; rect.x -= 14 * 3; j -= 3; GUI.DrawTexture(rect, treeMapLevel4Texture); rect.width = 14; } } HierarchyColorUtils.clearColor(); } } } } ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Component/TreeMapComponent.cs.meta ================================================ fileFormatVersion: 2 guid: 3956b2178bf9e494d9b0f059378da9bd MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Component/VerticesAndTrianglesCountComponent.cs ================================================ using System; using System.Collections.Generic; using UnityEngine; using UnityEditor; using VirtueSky.Hierarchy.HComponent.Base; using VirtueSky.Hierarchy.Data; namespace VirtueSky.Hierarchy.HComponent { public class VerticesAndTrianglesCountComponent: BaseComponent { // PRIVATE private GUIStyle labelStyle; private Color verticesLabelColor; private Color trianglesLabelColor; private bool calculateTotalCount; private bool showTrianglesCount; private bool showVerticesCount; private HierarchySize labelSize; // CONSTRUCTOR public VerticesAndTrianglesCountComponent () { labelStyle = new GUIStyle(); labelStyle.clipping = TextClipping.Clip; labelStyle.alignment = TextAnchor.MiddleRight; HierarchySettings.getInstance().addEventListener(HierarchySetting.VerticesAndTrianglesShow , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.VerticesAndTrianglesShowDuringPlayMode , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.VerticesAndTrianglesCalculateTotalCount , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.VerticesAndTrianglesShowTriangles , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.VerticesAndTrianglesShowVertices , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.VerticesAndTrianglesLabelSize , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.VerticesAndTrianglesVerticesLabelColor , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.VerticesAndTrianglesTrianglesLabelColor , settingsChanged); settingsChanged(); } // PRIVATE private void settingsChanged() { enabled = HierarchySettings.getInstance().get(HierarchySetting.VerticesAndTrianglesShow); showComponentDuringPlayMode = HierarchySettings.getInstance().get(HierarchySetting.VerticesAndTrianglesShowDuringPlayMode); calculateTotalCount = HierarchySettings.getInstance().get(HierarchySetting.VerticesAndTrianglesCalculateTotalCount); showTrianglesCount = HierarchySettings.getInstance().get(HierarchySetting.VerticesAndTrianglesShowTriangles); showVerticesCount = HierarchySettings.getInstance().get(HierarchySetting.VerticesAndTrianglesShowVertices); verticesLabelColor = HierarchySettings.getInstance().getColor(HierarchySetting.VerticesAndTrianglesVerticesLabelColor); trianglesLabelColor = HierarchySettings.getInstance().getColor(HierarchySetting.VerticesAndTrianglesTrianglesLabelColor); labelSize = (HierarchySize)HierarchySettings.getInstance().get(HierarchySetting.VerticesAndTrianglesLabelSize); #if UNITY_2019_1_OR_NEWER labelStyle.fontSize = labelSize == HierarchySize.Big ? 7 : 6; rect.width = labelSize == HierarchySize.Big ? 24 : 22; #else labelStyle.fontSize = labelSize == QHierarchySize.Big ? 9 : 8; rect.width = labelSize == QHierarchySize.Big ? 33 : 25; #endif } // DRAW public override LayoutStatus layout(GameObject gameObject, ObjectList objectList, Rect selectionRect, ref Rect curRect, float maxWidth) { if (maxWidth < rect.width) { return LayoutStatus.Failed; } else { curRect.x -= rect.width + 2; rect.x = curRect.x; rect.y = curRect.y; #if UNITY_2019_1_OR_NEWER rect.y += labelSize == HierarchySize.Big ? 2 : 1; #endif return LayoutStatus.Success; } } public override void draw(GameObject gameObject, ObjectList objectList, Rect selectionRect) { int vertexCount = 0; int triangleCount = 0; MeshFilter[] meshFilterArray = calculateTotalCount ? gameObject.GetComponentsInChildren(true) : gameObject.GetComponents(); for (int i = 0; i < meshFilterArray.Length; i++) { Mesh sharedMesh = meshFilterArray[i].sharedMesh; if (sharedMesh != null) { if (showVerticesCount) vertexCount += sharedMesh.vertexCount; if (showTrianglesCount) triangleCount += sharedMesh.triangles.Length; } } SkinnedMeshRenderer[] skinnedMeshRendererArray = calculateTotalCount ? gameObject.GetComponentsInChildren(true) : gameObject.GetComponents(); for (int i = 0; i < skinnedMeshRendererArray.Length; i++) { Mesh sharedMesh = skinnedMeshRendererArray[i].sharedMesh; if (sharedMesh != null) { if (showVerticesCount) vertexCount += sharedMesh.vertexCount; if (showTrianglesCount) triangleCount += sharedMesh.triangles.Length; } } triangleCount /= 3; if (vertexCount > 0 || triangleCount > 0) { if (showTrianglesCount && showVerticesCount) { rect.y -= 4; labelStyle.normal.textColor = verticesLabelColor; EditorGUI.LabelField(rect, getCountString(vertexCount), labelStyle); rect.y += 8; labelStyle.normal.textColor = trianglesLabelColor; EditorGUI.LabelField(rect, getCountString(triangleCount), labelStyle); } else if (showVerticesCount) { labelStyle.normal.textColor = verticesLabelColor; EditorGUI.LabelField(rect, getCountString(vertexCount), labelStyle); } else { labelStyle.normal.textColor = trianglesLabelColor; EditorGUI.LabelField(rect, getCountString(triangleCount), labelStyle); } } } // PRIVATE private string getCountString(int count) { if (count < 1000) return count.ToString(); else if (count < 1000000) { if (count > 100000) return (count / 1000.0f).ToString("0") + "k"; else return (count / 1000.0f).ToString("0.0") + "k"; } else { if (count > 10000000) return (count / 1000.0f).ToString("0") + "M"; else return (count / 1000000.0f).ToString("0.0") + "M"; } } } } ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Component/VerticesAndTrianglesCountComponent.cs.meta ================================================ fileFormatVersion: 2 guid: 087cec645530b2541832d66aeab19caa MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Component/VisibilityComponent.cs ================================================ using System; using System.Collections.Generic; using UnityEngine; using UnityEditor; using VirtueSky.Hierarchy.HComponent.Base; using VirtueSky.Hierarchy; using VirtueSky.Hierarchy.Helper; using VirtueSky.Hierarchy.Data; namespace VirtueSky.Hierarchy.HComponent { public class VisibilityComponent: BaseComponent { // PRIVATE private Color activeColor; private Color inactiveColor; private Color specialColor; private Texture2D visibilityButtonTexture; private Texture2D visibilityOffButtonTexture; private int targetVisibilityState = -1; // CONSTRUCTOR public VisibilityComponent() { rect.width = 18; visibilityButtonTexture = HierarchyResources.getInstance().getTexture(HierarchyTexture.HierarchyVisibilityButton); visibilityOffButtonTexture = HierarchyResources.getInstance().getTexture(HierarchyTexture.HierarchyVisibilityOffButton); HierarchySettings.getInstance().addEventListener(HierarchySetting.VisibilityShow , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.VisibilityShowDuringPlayMode , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.AdditionalActiveColor , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.AdditionalInactiveColor , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.AdditionalSpecialColor , settingsChanged); settingsChanged(); } private void settingsChanged() { enabled = HierarchySettings.getInstance().get(HierarchySetting.VisibilityShow); showComponentDuringPlayMode = HierarchySettings.getInstance().get(HierarchySetting.VisibilityShowDuringPlayMode); activeColor = HierarchySettings.getInstance().getColor(HierarchySetting.AdditionalActiveColor); inactiveColor = HierarchySettings.getInstance().getColor(HierarchySetting.AdditionalInactiveColor); specialColor = HierarchySettings.getInstance().getColor(HierarchySetting.AdditionalSpecialColor); } // DRAW public override LayoutStatus layout(GameObject gameObject, ObjectList objectList, Rect selectionRect, ref Rect curRect, float maxWidth) { if (maxWidth < 18) { return LayoutStatus.Failed; } else { curRect.x -= 18; rect.x = curRect.x; rect.y = curRect.y; return LayoutStatus.Success; } } public override void disabledHandler(GameObject gameObject, ObjectList objectList) { if (objectList != null) { if (gameObject.activeSelf && objectList.editModeVisibileObjects.Contains(gameObject)) { objectList.editModeVisibileObjects.Remove(gameObject); gameObject.SetActive(false); EditorUtility.SetDirty(gameObject); } else if (!gameObject.activeSelf && objectList.editModeInvisibleObjects.Contains(gameObject)) { objectList.editModeInvisibleObjects.Remove(gameObject); gameObject.SetActive(true); EditorUtility.SetDirty(gameObject); } } } public override void draw(GameObject gameObject, ObjectList objectList, Rect selectionRect) { int visibility = gameObject.activeSelf ? 1 : 0; bool editModeVisibleObjectsContains = isEditModeVisibile(gameObject, objectList); bool editModeInvisibleObjectsContains = isEditModeInvisibile(gameObject, objectList); if (!EditorApplication.isPlayingOrWillChangePlaymode && ((!gameObject.activeSelf && editModeVisibleObjectsContains) || (gameObject.activeSelf && editModeInvisibleObjectsContains))) gameObject.SetActive(!gameObject.activeSelf); Transform transform = gameObject.transform; while (transform.parent != null) { transform = transform.parent; if (!transform.gameObject.activeSelf) { visibility = 2; break; } } if (!EditorApplication.isPlayingOrWillChangePlaymode && (editModeVisibleObjectsContains || editModeInvisibleObjectsContains)) { if (visibility == 0) { HierarchyColorUtils.setColor(specialColor); GUI.DrawTexture(rect, visibilityOffButtonTexture); } else if (visibility == 1) { HierarchyColorUtils.setColor(specialColor); GUI.DrawTexture(rect, visibilityButtonTexture); } else { HierarchyColorUtils.setColor(specialColor, 1.0f, 0.4f); GUI.DrawTexture(rect, editModeVisibleObjectsContains ? visibilityButtonTexture : visibilityOffButtonTexture); } } else { if (visibility == 0) { HierarchyColorUtils.setColor(inactiveColor); GUI.DrawTexture(rect, visibilityOffButtonTexture); } else if (visibility == 1) { HierarchyColorUtils.setColor(activeColor); GUI.DrawTexture(rect, visibilityButtonTexture); } else { if (gameObject.activeSelf) { HierarchyColorUtils.setColor(activeColor, 0.65f, 0.65f); GUI.DrawTexture(rect, visibilityButtonTexture); } else { HierarchyColorUtils.setColor(inactiveColor, 0.85f, 0.85f); GUI.DrawTexture(rect, visibilityOffButtonTexture); } } } HierarchyColorUtils.clearColor(); } public override void eventHandler(GameObject gameObject, ObjectList objectList, Event currentEvent) { if (currentEvent.isMouse && currentEvent.button == 0 && rect.Contains(currentEvent.mousePosition)) { if (currentEvent.type == EventType.MouseDown) { targetVisibilityState = ((!gameObject.activeSelf) == true ? 1 : 0); } else if (currentEvent.type == EventType.MouseDrag && targetVisibilityState != -1) { if (targetVisibilityState == (gameObject.activeSelf == true ? 1 : 0)) return; } else { targetVisibilityState = -1; return; } bool showWarning = HierarchySettings.getInstance().get(HierarchySetting.AdditionalShowModifierWarning); List targetGameObjects = new List(); if (currentEvent.control || currentEvent.command) { if (currentEvent.shift) { 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")) { getGameObjectListRecursive(gameObject, ref targetGameObjects); } } else if (currentEvent.alt) { if (gameObject.transform.parent != null) { 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")) { getGameObjectListRecursive(gameObject.transform.parent.gameObject, ref targetGameObjects, 1); targetGameObjects.Remove(gameObject.transform.parent.gameObject); } } else { Debug.Log("This action for root objects is supported for Unity3d 5.3.3 and above"); return; } } else { getGameObjectListRecursive(gameObject, ref targetGameObjects, 0); } } else if (currentEvent.shift) { 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")) { getGameObjectListRecursive(gameObject, ref targetGameObjects); } } else if (currentEvent.alt) { if (gameObject.transform.parent != null) { 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")) { getGameObjectListRecursive(gameObject.transform.parent.gameObject, ref targetGameObjects, 1); targetGameObjects.Remove(gameObject.transform.parent.gameObject); } } else { Debug.Log("This action for root objects is supported for Unity3d 5.3.3 and above"); return; } } else { if (Selection.Contains(gameObject)) { targetGameObjects.AddRange(Selection.gameObjects); } else { getGameObjectListRecursive(gameObject, ref targetGameObjects, 0); }; } setVisibility(targetGameObjects, objectList, !gameObject.activeSelf, currentEvent.control || currentEvent.command); currentEvent.Use(); } } // PRIVATE private bool isEditModeVisibile(GameObject gameObject, ObjectList objectList) { return objectList == null ? false : objectList.editModeVisibileObjects.Contains(gameObject); } private bool isEditModeInvisibile(GameObject gameObject, ObjectList objectList) { return objectList == null ? false : objectList.editModeInvisibleObjects.Contains(gameObject); } private void setVisibility(List gameObjects, ObjectList objectList, bool targetVisibility, bool editMode) { if (gameObjects.Count == 0) return; if (objectList == null && editMode) objectList = HierarchyObjectListManager.getInstance().getObjectList(gameObjects[0], true); if (objectList != null) Undo.RecordObject(objectList, "visibility change"); for (int i = gameObjects.Count - 1; i >= 0; i--) { GameObject curGameObject = gameObjects[i]; Undo.RecordObject(curGameObject, "visibility change"); if (editMode) { if (!targetVisibility) { objectList.editModeVisibileObjects.Remove(curGameObject); if (!objectList.editModeInvisibleObjects.Contains(curGameObject)) objectList.editModeInvisibleObjects.Add(curGameObject); } else { objectList.editModeInvisibleObjects.Remove(curGameObject); if (!objectList.editModeVisibileObjects.Contains(curGameObject)) objectList.editModeVisibileObjects.Add(curGameObject); } } else if (objectList != null) { objectList.editModeVisibileObjects.Remove(curGameObject); objectList.editModeInvisibleObjects.Remove(curGameObject); } curGameObject.SetActive(targetVisibility); EditorUtility.SetDirty(curGameObject); } } } } ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Component/VisibilityComponent.cs.meta ================================================ fileFormatVersion: 2 guid: c73020ec99bb4ad48bcafd323fc4d08a MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Component.meta ================================================ fileFormatVersion: 2 guid: 745985dd54264b14faabbb60338e354e folderAsset: yes timeCreated: 1515657177 licenseType: Store DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Data/HierarchyResources.cs ================================================ using UnityEngine; using UnityEditor; using System; using System.Collections; using System.Collections.Generic; namespace VirtueSky.Hierarchy.Data { public enum HierarchyTexture { HierarchyCheckBoxChecked = 0, HierarchyCheckBoxUnchecked = 1, HierarchyColorButton = 2, HierarchyColorPalette = 3, HierarchyComponentUnknownIcon = 4, HierarchyDragButton = 5, HierarchyErrorIcon = 6, HierarchyLockButton = 7, HierarchyMonoBehaviourIcon = 8, HierarchyPrefabIcon = 9, HierarchyRendererButton = 10, HierarchyRestoreButton = 11, HierarchyTreeMapCurrent = 12, HierarchyTreeMapLast = 13, HierarchyTreeMapLevel = 14, HierarchyTreeMapLevel4 = 15, HierarchyTreeMapObject = 16, HierarchyTrimIcon = 17, HierarchyVisibilityButton = 18, HierarchyVisibilityOffButton = 19, HierarchyTreeMapLine = 20, }; public enum HierarchyColor { BackgroundDark, Background, Gray, GrayLight, GrayDark } public class HierarchyResources { // SINGLETON private static HierarchyResources instance; public static HierarchyResources getInstance() { if (instance == null) instance = new HierarchyResources(); return instance; } // PRIVATE private Dictionary textures; private Dictionary resourcesCommon = new Dictionary() { { HierarchyTexture.HierarchyColorButton, "iVBORw0KGgoAAAANSUhEUgAAAAgAAAAQCAYAAAArij59AAAAWUlEQVQoFWP8//8/Az7AhE8SJDcYFLBAHakLpIOB2AGIDwDxWiC+DMQMMAUgSR+QABDAaLACmC8cwFIIAs6HKTiAkAOz4HyYFSA7QcABiA8AMYzPwDgUghoAHO8PN+sTbZ4AAAAASUVORK5CYII=" }, { 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" }, { HierarchyTexture.HierarchyComponentUnknownIcon, "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABGElEQVQ4EWNgoBAwQvVLAWk1Isy6BVTzDFkdC5Sj9ujZy/3IEsjsD5+/MixdtJChs7XRESoON4QJWSEuNgc7K0NwRBRDbVMbyBKQS0EuBgPiDGBjYxDg4WLwDQxmqG/tghmC24CP334yZM3fziCfN4nBp3sFw+XHrxg42CGGOLt7Qu3G44Jlx64wHLn5iGFpdiCDnAg/Q9a87WDVIEPEhPhRDIAFIoqgjbosg66sGAOIBtkOMgwGuDjYYUwwjdUAkGYQePT2I8P0PWcYMl1MwHxsBN5ArFyxD+ySTBdjbHrBYngNAKnAZztIHq8BNupyIDV4AV4DOjYdBQciPhOwBiJMw8NJeTAmThqvC3DqQpIgNTfCtMJzJQDmf0F9Rh99OwAAAABJRU5ErkJggg==" }, { HierarchyTexture.HierarchyErrorIcon, "iVBORw0KGgoAAAANSUhEUgAAAAcAAAAQCAYAAADagWXwAAAANklEQVQYGWP8/fs3Ay7AhEsCJE605H+gYhCGA6J1wnXAGAOhkwVmOZBmRGKDmUQ7iLRAIN9OAA9DBxP0TyMiAAAAAElFTkSuQmCC" }, { HierarchyTexture.HierarchyLockButton, "iVBORw0KGgoAAAANSUhEUgAAAA0AAAAQCAYAAADNo/U5AAAAtklEQVQoFb2QsQ0CMQxFY6Cgp+EmYA4WgDVYhtuFLViBCagoKY/wXxRHXJDCQcGXvuxvf599sRhj+BaLaqCT3osr8SaexKs4Bpsyd4p38RVo6u5J0UWnBoazuBGXOaKp03dv8OSgImDAa0Q0oF/qs3zsOsfL+Pjg2vup7UOV94PU2l4cxBbo40snmpJB352y8SHfnBswvw2Y2ZZmheIrSWVoyv8N/fwQR/0AL9gCfXwJbPJ8cnwCewTKXVfaQ3EAAAAASUVORK5CYII=" }, { HierarchyTexture.HierarchyMonoBehaviourIcon, "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAMUlEQVQ4EWP8//8/AyWABagZZEIhuYYwkasRpm/UAAaG0TAYDQNQfgClgz+wjEEODQAZqgWLOZX9TgAAAABJRU5ErkJggg==" }, { HierarchyTexture.HierarchyPrefabIcon, "iVBORw0KGgoAAAANSUhEUgAAAAkAAAAQCAYAAADESFVDAAAAd0lEQVQoFY2RUQqAMAxDV/GeHkU8ijfzHv3QphIJm7AWtpbtkWTM3L3NapkBuC9Ba4D3j5rpGSDU8bbcd5lzLNmVINpBdhMb5sxsvdIZ4BVLMzYqMayqfcKAUjI6LKA0VG83ADgoQSYfzBepWkZhcFwwm0I5l+weLU0O7oJcg0oAAAAASUVORK5CYII=" }, { HierarchyTexture.HierarchyRendererButton, "iVBORw0KGgoAAAANSUhEUgAAAAwAAAAQCAYAAAAiYZ4HAAAAdElEQVQoFWP8/v07AwsLCwOxgIlYhTB1JGsAuUUFiGVgJhCgDwCdz3KbgCKYtCOIAXYSKyurIxAzggRwsUFyIIDsBwewCITAxWZg/P37938khfiYICcdGHUSviD68+ePKlD+DihpgCMMn2JkOeSIQxbHyQYAcE0cpIy04qQAAAAASUVORK5CYII=" }, { HierarchyTexture.HierarchyRestoreButton, "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAA3klEQVQ4Ec1RMQ7CMAxMUtj4CSPiATyADzB2QWx8gAlF4geIpTO/YEZIbAz8gxWFuyip3KRR2cDS1fad7dSJttaqkjnnvKS1LpUoU1S+FP53wBobXIFXAGNymfWtwMIdcDfGLAjGgcuGjCC0xlvHjR9AnIFNKyh1C3ENfxJ89gpbihj0DN7X8hmBBvyUh0jIFd6onkEc0wPMB02uUOGU2LRCJ3M/gCfCauQPT4iP/APSVdCiZzoHjsASaICOyT+Igm+Oe4K8hJP3iDsXyIa+AeSlTWSSxukKqT6Y/37AB6sOP8hny1/VAAAAAElFTkSuQmCC" }, { HierarchyTexture.HierarchyTreeMapCurrent, "iVBORw0KGgoAAAANSUhEUgAAAA4AAAAQCAYAAAAmlE46AAAAQ0lEQVQoFWNgwA+E/wMBUIkwujImdAFi+aMa8YQUCx45dCmUKCFKIzAq36CbQpRGRkZGEbI0QjW9RdY8mgCQQwONDQApiglJmB+fmgAAAABJRU5ErkJggg==" }, { HierarchyTexture.HierarchyTreeMapLast, "iVBORw0KGgoAAAANSUhEUgAAAA4AAAAQCAYAAAAmlE46AAAAPUlEQVQoFWNgwA+E/wMBUIkwujImdAFi+aMa8YQUCx45dCmUKCFKIzAq36CbwogugMbnBvI50MRGuTQLAQD/rQhHffk54gAAAABJRU5ErkJggg==" }, { HierarchyTexture.HierarchyTreeMapLevel, "iVBORw0KGgoAAAANSUhEUgAAAA4AAAAQCAYAAAAmlE46AAAAJElEQVQoFWNgwA8k/wMBUIkkujImdAFi+aMa8YTUaOCM8MABAI00BE1+cZ4yAAAAAElFTkSuQmCC" }, { HierarchyTexture.HierarchyTreeMapLevel4, "iVBORw0KGgoAAAANSUhEUgAAADgAAAAQCAYAAABDebxFAAAATklEQVRIDe2SMQoAMAgDpV/w/29t3QWzpnKOGiHmjJgrb1VJcpa1qc3eadaWNTjwd6AQhKB5AryoOSBpD4IyInMBBM0BSXsQlBGZC9YTfL7XEKcUdfHdAAAAAElFTkSuQmCC" }, { HierarchyTexture.HierarchyTreeMapObject, "iVBORw0KGgoAAAANSUhEUgAAAA4AAAAQCAYAAAAmlE46AAABnUlEQVQoFdVSTW/aQBR83vX6K9iOkAqmQVUQyoUrUg7cg/qLkTjliDggVfTKZ9rKiT9Q2hjLLsTprMWBWL311Lcar/12Z+fN8xL9N6FUKlXxbQHOCTZmBqTAM/Dr9H6QG8+jPhgM7hqNxnW73b7wPK8mhGBxGKfbb9uX1WoVxnH8FfO8SrwaDoe3rusatu2Srovy0I+e53Zvum6v1/uw2Ww+gfhUJV4WRWEsl0uyrBp1Oh0yTUE/fJ+iICKs6a1Wq8BpTpXIuMLfsEEJgoCiKICqTsfjkegN5i8syrIMH8Sk8feBjFAFFA1KkoTDkyaYIKEByHPOy4ZWFQtd1RSmgA0FNIZIFoZgGCpXybAMKXaoKv5M0v1vprKSxFBQgcEEQwUWCTRrNpvtQNxxedpZvMa72K3X67ZpmTq8gcuY4zivh+Mhm0wm36fT6TjP822VmIdh+LBerxN4cZvNpq1pGvd9/3E0Gn1ZLBbjNE2XEMqrN0eKy5wJf91+v/8ZHbbw3+6jKJojL29O6fpvRKyVoeFZA2Qf9kAGoGX/GH8AjXiXWwSceRAAAAAASUVORK5CYII=" }, { HierarchyTexture.HierarchyTrimIcon, "iVBORw0KGgoAAAANSUhEUgAAAAcAAAAQCAYAAADagWXwAAAAOUlEQVQYGWP8//8/Ay7AhEsCJD5YJOHOR3cQXALdtSgS6JKMIAFkgG4sigJ0SZBGuAJsknCTaSQJAGHZBh0Iaq7CAAAAAElFTkSuQmCC" }, { HierarchyTexture.HierarchyVisibilityButton, "iVBORw0KGgoAAAANSUhEUgAAABIAAAAQCAYAAAAbBi9cAAABBklEQVQ4EdWTuw4BURCGXRqXXkmvoBXeg5dRU1MpNlHwBBoKUai1GhQKQkmDKKzv3+zIuhQk2/iTz4yZs+PMzIq6rhsJQ7EwiqjGfxQqctM2zOEEF1iCAxX4LA3bJ45twhWkEwxhAAeQbuBAGuw5z9qXKIk+mGY4GVBeuRSMwDTGUcyej5hTtxNY3SQLFVjDHmqQgA2YOjjqwquhjzwEf23iJ1dYk1rT2a4FsFMogVdI6w/njfQrvraWI26t7fCrkIQtmN5a09U00J6dwAaHrfzXw9ZhDa4Btv4zvman9R9BsvU/bYz4Y2vewBSAArRgDtrgBRbgQBmCZx++Wvr8pv4YDe1PeweSfPysEmODwwAAAABJRU5ErkJggg==" }, { HierarchyTexture.HierarchyVisibilityOffButton, "iVBORw0KGgoAAAANSUhEUgAAABIAAAAQCAYAAAAbBi9cAAABdUlEQVQ4Ea3TvS8EQRjH8dvLHZGoLvQqQaKReKlEp6RA7Q9QafwDGp1EIgqRy3mJhASJSiMaCi4Roj2rOAonkmtEgvX9ze6zVrKh2Sf5zPPM7Mxkd+bOC4Igl0Xks9hEe2S+0TibVlLersCY/Bv2Rs/MnMR2tGKAfIkafJxjET1IDx12pI+sKCOPLdzhAu9QKC+hCFvncrKzzEOLfQp71kJdwpk9JB+hFTYnZ8VCYtIrdR2H0cQ58iza8QSLFQoPbg+dkb57LPHhV9RDmMAe1tCNN5zAop9C81zoRoqRcCRs66R7TEG/2BkovDC5Vi+htS7UucV12HXtIG0J82hiGmUodLsWjxRV69gZ6UCP7ePJp2iDzqAXTVSg+Zu4gS7A1seHrQHdwiq+oNCh72AdDSh2oZ+GDj7eRPWvTvRwmKzFNXxC8YAN+NDVx7dF7fZI28jGCkzqQCf06RrvwgsOor7N/fN/9MFBNuLDDAufNILRsPvTfgP0LsP1SIPKHwAAAABJRU5ErkJggg==" }, { HierarchyTexture.HierarchyTreeMapLine, "iVBORw0KGgoAAAANSUhEUgAAAA4AAAAQCAMAAAARSr4IAAAACVBMVEX///8AAAD///9+749PAAAAAnRSTlMAE/ItjOYAAAAWSURBVHgBY6AbYEQAEJcJDhjRZWkJABQbACw6WoebAAAAAElFTkSuQmCC" }, }; private Dictionary resourcesDark = new Dictionary() { { HierarchyTexture.HierarchyCheckBoxChecked, "iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAABV0lEQVQoFWO0sLD4zwAETEyMDECEF/wDqvwHIoCABUS42wkwlKRKM3CwM4G4OMGPn/8YemY/Zdh56APQIqA1JSnSDDxczAwszIx4MUgNSC3YdSDncXDgtundhz8Mdx7+hLsCpBakB7cOqNJpS18zpFY9ZFi26R1cM4iBofHM5W/AAICouXzzO8PeY5/BHE1lDogglETROHf1G4bSjicMC9e/Zfjz5z9D9+yXYGXOVrwMhtpcKBrBoQoT0dfgYljG9I5h0bq3DM9f/WZ4/PwXAyfQTxlRojAlcBrFRhNdLoaMSIiiPUc/gRUlhwoziAiimA8WR9EIEgn1EmTQVOFg+A+MZxV5doZAN0GwQnQC0yigimmNcgy7jnxikBZnA8YZuhYInwWUgn78+MfAw82MosLNhg+FD+OA1IL0MIHSXs+cpwxfvv1l+PP3P14MUgNSC9LDSG4iBwCgfYRJ3KYMwgAAAABJRU5ErkJggg==" }, { HierarchyTexture.HierarchyCheckBoxUnchecked, "iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAAgElEQVQoFe2SywkAIQxE46cHO/Bu/53YgdaguPsCgpd1hb1uIBjxDSNhTEppyF3GGI7XGkNx8ZAhBIkxinNuK+y9S85ZSilicULkvVdX7k8NA8u7xeLNaf3GZFW4PpzOv3CzqW/LIRGnNVlL9ohRa02Ydw0DC6NZJXu11iNTRNQFcsdGKGm8LNQAAAAASUVORK5CYII=" }, { HierarchyTexture.HierarchyDragButton, "iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAfElEQVQ4EWM0NjZmoCZgoqZhILNGoIEsaGFoDuRroIkR4t4AKjgJU4RuoMb///8XwCSJoRkZGROA6nAaeMPBwYEYc+BqDh48CHIhHGC48MCBA3BJYhhAF4KCaNSFiMDSoHoYQpMBwgrCLLyxDIoteIwRNgtTxQgsHAa/lwH5tiOYn8m38AAAAABJRU5ErkJggg==" }, }; private Dictionary resourcesLight = new Dictionary() { { HierarchyTexture.HierarchyCheckBoxChecked, "iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAABOUlEQVQoFY2Sva6CQBCFz4XVQGFjgiZQGKiJnYmFBQVPAo9l7RvQUZAgvAChpqAiGkNDpQLX2bjkkhuMW+zM7pwv85P58X2/x+swxiBJErmTp+s6PJ9PHmd0Hw4HrFYrzGazSYgCj8cDl8sFSZJQIgZN06AoykeIgrIsc+27Ognz+XwSapoGVVUNcdJSS5+besnDMMTxeESapgNMzj+wKArQEOiUZYk8z7mv6zq34hqBURThdDrhfD6jbVsEQcB1tm3DNE3BcMunKn42mw0vKY5j1HWN2+3G+3ddV0gGO8poWRaESJToOA4Wi8UACGcE0ud+v4dhGOj7Huv1GrvdTmhHdlSqiHiehyzLsFwuJ7eJ0QTv9ztUVRUct9vtdvQWD9ISw2j3rtfr1ytHWmJ4qe/dmyxLZPu75L/vGnGpeAWI1gAAAABJRU5ErkJggg==" }, { HierarchyTexture.HierarchyCheckBoxUnchecked, "iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAAjklEQVQoFe2STRJDERCEOwzlApzGbVzVabwboCRp9ezeT5J1ZmGU+Roz1Y+U0hPvEBEopbg9jTEGeu+zLlxjjAghwBhzKmKhtYZSCnLOfEjgvYdz7lLEotZ6svvvFKy1t6IFkGVL100t+iD/hQdDWUe/D4c2qrWui24zWWqE3tu27WPLkaVmenX33lcmfwFMazT7V5IT7wAAAABJRU5ErkJggg==" }, { HierarchyTexture.HierarchyDragButton, "iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAATklEQVQ4EWM8ceIEAzUBEzUNA5k1aiDlIcqCxYj/WMTwCTEiS7Js27oVmU8xmxFLOhx1IWnBSv0wxGI/SjLAIo9XaDQv4w0eoiQHfxgCAGQPE/BDNfMZAAAAAElFTkSuQmCC" }, }; private Dictionary colors; private Dictionary colorsDark = new Dictionary() { { HierarchyColor.BackgroundDark, new Color(0.15f, 0.15f, 0.15f) }, { HierarchyColor.Background , new Color(0.22f, 0.22f, 0.22f) }, { HierarchyColor.Gray , new Color(0.6f, 0.6f, 0.6f) }, { HierarchyColor.GrayLight , new Color(0.8f, 0.8f, 0.8f) }, { HierarchyColor.GrayDark , new Color(0.4f, 0.4f, 0.4f) }, }; private Dictionary colorsLight = new Dictionary() { { HierarchyColor.BackgroundDark, new Color(0.88f, 0.88f, 0.88f) }, { HierarchyColor.Background , new Color(0.761f, 0.761f, 0.761f) }, { HierarchyColor.Gray , new Color(0.3f, 0.3f, 0.3f) }, { HierarchyColor.GrayLight , new Color(0.1f, 0.1f, 0.1f) }, { HierarchyColor.GrayDark , new Color(0.55f, 0.55f, 0.55f) }, }; // CONSTRUCTOR private HierarchyResources() { textures = new Dictionary(); foreach (KeyValuePair resourcePair in resourcesCommon) { Texture2D texture = new Texture2D(1,1, TextureFormat.ARGB32, false, false); texture.hideFlags = HideFlags.HideAndDontSave; texture.LoadImage(Convert.FromBase64String(resourcePair.Value)); textures.Add(resourcePair.Key, texture); } Dictionary resources = EditorGUIUtility.isProSkin ? resourcesDark : resourcesLight; foreach (KeyValuePair resourcePair in resources) { Texture2D texture = new Texture2D(1,1, TextureFormat.ARGB32, false, false); texture.hideFlags = HideFlags.HideAndDontSave; texture.LoadImage(Convert.FromBase64String(resourcePair.Value)); textures.Add(resourcePair.Key, texture); } colors = EditorGUIUtility.isProSkin ? colorsDark : colorsLight; } // PUBLIC public Texture2D getTexture(HierarchyTexture textureName) { return textures[textureName]; } public Color getColor(HierarchyColor color) { return colors[color]; } } } ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Data/HierarchyResources.cs.meta ================================================ fileFormatVersion: 2 guid: 387ed2783d685b048a858216512aa0c3 timeCreated: 1474883135 licenseType: Store MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Data/HierarchySettings.cs ================================================ using UnityEngine; using UnityEditor; using System.Collections; using System.Collections.Generic; using VirtueSky.Hierarchy; using VirtueSky.Hierarchy.Helper; using System.Text; namespace VirtueSky.Hierarchy.Data { public enum HierarchySetting { TreeMapShow = 0, TreeMapColor = 77, TreeMapEnhanced = 78, TreeMapTransparentBackground = 60, MonoBehaviourIconShow = 4, MonoBehaviourIconShowDuringPlayMode = 18, MonoBehaviourIconIgnoreUnityMonobehaviour = 45, MonoBehaviourIconColor = 82, SeparatorShow = 8, SeparatorShowRowShading = 50, SeparatorColor = 80, SeparatorEvenRowShadingColor = 79, SeparatorOddRowShadingColor = 81, VisibilityShow = 1, VisibilityShowDuringPlayMode = 15, LockShow = 2, LockShowDuringPlayMode = 16, LockPreventSelectionOfLockedObjects = 41, StaticShow = 12, StaticShowDuringPlayMode = 25, ErrorShow = 6, ErrorShowDuringPlayMode = 20, ErrorShowIconOnParent = 27, ErrorShowScriptIsMissing = 28, ErrorShowReferenceIsNull = 29, ErrorShowReferenceIsMissing = 58, ErrorShowStringIsEmpty = 30, ErrorShowMissingEventMethod = 31, ErrorShowWhenTagOrLayerIsUndefined = 32, ErrorIgnoreString = 33, ErrorShowForDisabledComponents = 44, ErrorShowForDisabledGameObjects = 59, RendererShow = 7, RendererShowDuringPlayMode = 21, PrefabShow = 13, PrefabShowBreakedPrefabsOnly = 51, TagAndLayerShow = 5, TagAndLayerShowDuringPlayMode = 19, TagAndLayerSizeShowType = 68, TagAndLayerType = 34, TagAndLayerSizeType = 35, TagAndLayerSizeValuePixel = 36, TagAndLayerAligment = 37, TagAndLayerSizeValueType = 46, TagAndLayerSizeValuePercent = 47, TagAndLayerLabelSize = 48, TagAndLayerTagLabelColor = 66, TagAndLayerLayerLabelColor = 67, TagAndLayerLabelAlpha = 69, ColorShow = 9, ColorShowDuringPlayMode = 22, GameObjectIconShow = 3, GameObjectIconShowDuringPlayMode = 17, GameObjectIconSize = 63, TagIconShow = 14, TagIconShowDuringPlayMode = 26, TagIconListFoldout = 84, TagIconList = 40, TagIconSize = 62, LayerIconShow = 85, LayerIconShowDuringPlayMode = 86, LayerIconListFoldout = 87, LayerIconList = 88, LayerIconSize = 89, ChildrenCountShow = 11, ChildrenCountShowDuringPlayMode = 24, ChildrenCountLabelSize = 61, ChildrenCountLabelColor = 70, VerticesAndTrianglesShow = 53, VerticesAndTrianglesShowDuringPlayMode = 54, VerticesAndTrianglesCalculateTotalCount = 55, VerticesAndTrianglesShowTriangles = 56, VerticesAndTrianglesShowVertices = 64, VerticesAndTrianglesLabelSize = 57, VerticesAndTrianglesVerticesLabelColor = 71, VerticesAndTrianglesTrianglesLabelColor = 72, ComponentsShow = 10, ComponentsShowDuringPlayMode = 23, ComponentsIconSize = 65, ComponentsIgnore = 90, ComponentsOrder = 38, AdditionalIdentation = 39, AdditionalShowHiddenQHierarchyObjectList = 42, AdditionalShowModifierWarning = 43, AdditionalShowObjectListContent = 49, AdditionalHideIconsIfNotFit = 52, AdditionalBackgroundColor = 73, AdditionalActiveColor = 74, AdditionalInactiveColor = 75, AdditionalSpecialColor = 76, } public enum HierarchyTagAndLayerType { Always = 0, OnlyIfNotDefault = 1 } public enum HierarchyTagAndLayerShowType { TagAndLayer = 0, Tag = 1, Layer = 2 } public enum HierarchyTagAndLayerAligment { Left = 0, Center = 1, Right = 2 } public enum HierarchyTagAndLayerSizeType { Pixel = 0, Percent = 1 } public enum HierarchyTagAndLayerLabelSize { Normal = 0, Big = 1, BigIfSpecifiedOnlyTagOrLayer = 2 } public enum HierarchySize { Normal = 0, Big = 1 } public enum HierarchySizeAll { Small = 0, Normal = 1, Big = 2 } public enum HierarchyComponentEnum { LockComponent = 0, VisibilityComponent = 1, StaticComponent = 2, ColorComponent = 3, ErrorComponent = 4, RendererComponent = 5, PrefabComponent = 6, TagAndLayerComponent = 7, GameObjectIconComponent = 8, TagIconComponent = 9, LayerIconComponent = 10, ChildrenCountComponent = 11, VerticesAndTrianglesCount = 12, SeparatorComponent = 1000, TreeMapComponent = 1001, MonoBehaviourIconComponent = 1002, ComponentsComponent = 1003 } public class TagTexture { public string tag; public Texture2D texture; public TagTexture(string tag, Texture2D texture) { this.tag = tag; this.texture = texture; } public static List loadTagTextureList() { List tagTextureList = new List(); string customTagIcon = HierarchySettings.getInstance().get(HierarchySetting.TagIconList); string[] customTagIconArray = customTagIcon.Split(new char[] { ';' }); List tags = new List(UnityEditorInternal.InternalEditorUtility.tags); for (int i = 0; i < customTagIconArray.Length - 1; i += 2) { string tag = customTagIconArray[i]; if (!tags.Contains(tag)) continue; string texturePath = customTagIconArray[i + 1]; Texture2D texture = (Texture2D)AssetDatabase.LoadAssetAtPath(texturePath, typeof(Texture2D)); if (texture != null) { TagTexture tagTexture = new TagTexture(tag, texture); tagTextureList.Add(tagTexture); } } return tagTextureList; } public static void saveTagTextureList(HierarchySetting setting, List tagTextureList) { string result = ""; for (int i = 0; i < tagTextureList.Count; i++) result += tagTextureList[i].tag + ";" + AssetDatabase.GetAssetPath(tagTextureList[i].texture.GetInstanceID()) + ";"; HierarchySettings.getInstance().set(setting, result); } } public class LayerTexture { public string layer; public Texture2D texture; public LayerTexture(string layer, Texture2D texture) { this.layer = layer; this.texture = texture; } public static List loadLayerTextureList() { List layerTextureList = new List(); string customTagIcon = HierarchySettings.getInstance().get(HierarchySetting.LayerIconList); string[] customLayerIconArray = customTagIcon.Split(new char[] { ';' }); List layers = new List(UnityEditorInternal.InternalEditorUtility.layers); for (int i = 0; i < customLayerIconArray.Length - 1; i += 2) { string layer = customLayerIconArray[i]; if (!layers.Contains(layer)) continue; string texturePath = customLayerIconArray[i + 1]; Texture2D texture = (Texture2D)AssetDatabase.LoadAssetAtPath(texturePath, typeof(Texture2D)); if (texture != null) { LayerTexture tagTexture = new LayerTexture(layer, texture); layerTextureList.Add(tagTexture); } } return layerTextureList; } public static void saveLayerTextureList(HierarchySetting setting, List layerTextureList) { string result = ""; for (int i = 0; i < layerTextureList.Count; i++) result += layerTextureList[i].layer + ";" + AssetDatabase.GetAssetPath(layerTextureList[i].texture.GetInstanceID()) + ";"; HierarchySettings.getInstance().set(setting, result); } } public delegate void SettingChangedHandler(); public class HierarchySettings { public bool inited = false; public Rect lastRect; public bool isProSkin; public int indentLevel; public Texture2D checkBoxChecked; public Texture2D checkBoxUnchecked; public Texture2D restoreButtonTexture; public Vector2 scrollPosition = new Vector2(); public Color separatorColor; public Color yellowColor; public float totalWidth; public HierarchyComponentsOrderList componentsOrderList; // CONST private const string PREFS_PREFIX = "QTools.QHierarchy_"; private const string PREFS_DARK = "Dark_"; private const string PREFS_LIGHT = "Light_"; public const string DEFAULT_ORDER = "0;1;2;3;4;5;6;7;8;9;10;11;12"; public const int DEFAULT_ORDER_COUNT = 13; private const string SETTINGS_FILE_NAME = "QSettingsObjectAsset"; // PRIVATE private HierarchySettingsObject settingsObject; private Dictionary defaultSettings = new Dictionary(); private HashSet skinDependedSettings = new HashSet(); private Dictionary settingChangedHandlerList = new Dictionary(); // SINGLETON private static HierarchySettings instance; public static HierarchySettings getInstance() { if (instance == null) instance = new HierarchySettings(); return instance; } // CONSTRUCTOR private HierarchySettings() { string[] paths = AssetDatabase.FindAssets(SETTINGS_FILE_NAME); for (int i = 0; i < paths.Length; i++) { settingsObject = (HierarchySettingsObject)AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(paths[i]), typeof(HierarchySettingsObject)); if (settingsObject != null) break; } if (settingsObject == null) { settingsObject = ScriptableObject.CreateInstance(); string path = AssetDatabase.GetAssetPath(MonoScript.FromScriptableObject(settingsObject)); path = path.Substring(0, path.LastIndexOf("/")); AssetDatabase.CreateAsset(settingsObject, path + "/" + SETTINGS_FILE_NAME + ".asset"); AssetDatabase.SaveAssets(); } initSetting(HierarchySetting.TreeMapShow, true); initSetting(HierarchySetting.TreeMapColor, "39FFFFFF", "905D5D5D"); initSetting(HierarchySetting.TreeMapEnhanced, true); initSetting(HierarchySetting.TreeMapTransparentBackground, true); initSetting(HierarchySetting.MonoBehaviourIconShow, true); initSetting(HierarchySetting.MonoBehaviourIconShowDuringPlayMode, true); initSetting(HierarchySetting.MonoBehaviourIconIgnoreUnityMonobehaviour, true); initSetting(HierarchySetting.MonoBehaviourIconColor, "A01B6DBB"); initSetting(HierarchySetting.SeparatorShow, true); initSetting(HierarchySetting.SeparatorShowRowShading, true); initSetting(HierarchySetting.SeparatorColor, "FF303030", "48666666"); initSetting(HierarchySetting.SeparatorEvenRowShadingColor, "13000000", "08000000"); initSetting(HierarchySetting.SeparatorOddRowShadingColor, "00000000", "00FFFFFF"); initSetting(HierarchySetting.VisibilityShow, true); initSetting(HierarchySetting.VisibilityShowDuringPlayMode, true); initSetting(HierarchySetting.LockShow, true); initSetting(HierarchySetting.LockShowDuringPlayMode, false); initSetting(HierarchySetting.LockPreventSelectionOfLockedObjects, false); initSetting(HierarchySetting.StaticShow, true); initSetting(HierarchySetting.StaticShowDuringPlayMode, false); initSetting(HierarchySetting.ErrorShow, true); initSetting(HierarchySetting.ErrorShowDuringPlayMode, false); initSetting(HierarchySetting.ErrorShowIconOnParent, false); initSetting(HierarchySetting.ErrorShowScriptIsMissing, true); initSetting(HierarchySetting.ErrorShowReferenceIsNull, false); initSetting(HierarchySetting.ErrorShowReferenceIsMissing, true); initSetting(HierarchySetting.ErrorShowStringIsEmpty, false); initSetting(HierarchySetting.ErrorShowMissingEventMethod, true); initSetting(HierarchySetting.ErrorShowWhenTagOrLayerIsUndefined, true); initSetting(HierarchySetting.ErrorIgnoreString, ""); initSetting(HierarchySetting.ErrorShowForDisabledComponents, true); initSetting(HierarchySetting.ErrorShowForDisabledGameObjects, true); initSetting(HierarchySetting.RendererShow, false); initSetting(HierarchySetting.RendererShowDuringPlayMode, false); initSetting(HierarchySetting.PrefabShow, false); initSetting(HierarchySetting.PrefabShowBreakedPrefabsOnly, true); initSetting(HierarchySetting.TagAndLayerShow, true); initSetting(HierarchySetting.TagAndLayerShowDuringPlayMode, true); initSetting(HierarchySetting.TagAndLayerSizeShowType, (int)HierarchyTagAndLayerShowType.TagAndLayer); initSetting(HierarchySetting.TagAndLayerType, (int)HierarchyTagAndLayerType.OnlyIfNotDefault); initSetting(HierarchySetting.TagAndLayerAligment, (int)HierarchyTagAndLayerAligment.Left); initSetting(HierarchySetting.TagAndLayerSizeValueType, (int)HierarchyTagAndLayerSizeType.Pixel); initSetting(HierarchySetting.TagAndLayerSizeValuePercent, 0.25f); initSetting(HierarchySetting.TagAndLayerSizeValuePixel, 75); initSetting(HierarchySetting.TagAndLayerLabelSize, (int)HierarchyTagAndLayerLabelSize.Normal); initSetting(HierarchySetting.TagAndLayerTagLabelColor, "FFCCCCCC", "FF333333"); initSetting(HierarchySetting.TagAndLayerLayerLabelColor, "FFCCCCCC", "FF333333"); initSetting(HierarchySetting.TagAndLayerLabelAlpha, 0.35f); initSetting(HierarchySetting.ColorShow, true); initSetting(HierarchySetting.ColorShowDuringPlayMode, true); initSetting(HierarchySetting.GameObjectIconShow, false); initSetting(HierarchySetting.GameObjectIconShowDuringPlayMode, true); initSetting(HierarchySetting.GameObjectIconSize, (int)HierarchySizeAll.Small); initSetting(HierarchySetting.TagIconShow, false); initSetting(HierarchySetting.TagIconShowDuringPlayMode, true); initSetting(HierarchySetting.TagIconListFoldout, false); initSetting(HierarchySetting.TagIconList, ""); initSetting(HierarchySetting.TagIconSize, (int)HierarchySizeAll.Small); initSetting(HierarchySetting.LayerIconShow, false); initSetting(HierarchySetting.LayerIconShowDuringPlayMode, true); initSetting(HierarchySetting.LayerIconListFoldout, false); initSetting(HierarchySetting.LayerIconList, ""); initSetting(HierarchySetting.LayerIconSize, (int)HierarchySizeAll.Small); initSetting(HierarchySetting.ChildrenCountShow, false); initSetting(HierarchySetting.ChildrenCountShowDuringPlayMode, true); initSetting(HierarchySetting.ChildrenCountLabelSize, (int)HierarchySize.Normal); initSetting(HierarchySetting.ChildrenCountLabelColor, "FFCCCCCC", "FF333333"); initSetting(HierarchySetting.VerticesAndTrianglesShow, false); initSetting(HierarchySetting.VerticesAndTrianglesShowDuringPlayMode, false); initSetting(HierarchySetting.VerticesAndTrianglesCalculateTotalCount, false); initSetting(HierarchySetting.VerticesAndTrianglesShowTriangles, false); initSetting(HierarchySetting.VerticesAndTrianglesShowVertices, true); initSetting(HierarchySetting.VerticesAndTrianglesLabelSize, (int)HierarchySize.Normal); initSetting(HierarchySetting.VerticesAndTrianglesVerticesLabelColor, "FFCCCCCC", "FF333333"); initSetting(HierarchySetting.VerticesAndTrianglesTrianglesLabelColor, "FFCCCCCC", "FF333333"); initSetting(HierarchySetting.ComponentsShow, false); initSetting(HierarchySetting.ComponentsShowDuringPlayMode, false); initSetting(HierarchySetting.ComponentsIconSize, (int)HierarchySizeAll.Small); initSetting(HierarchySetting.ComponentsIgnore, ""); initSetting(HierarchySetting.ComponentsOrder, DEFAULT_ORDER); initSetting(HierarchySetting.AdditionalShowObjectListContent, false); initSetting(HierarchySetting.AdditionalShowHiddenQHierarchyObjectList, true); initSetting(HierarchySetting.AdditionalHideIconsIfNotFit, true); initSetting(HierarchySetting.AdditionalIdentation, 0); initSetting(HierarchySetting.AdditionalShowModifierWarning, true); #if UNITY_2019_1_OR_NEWER initSetting(HierarchySetting.AdditionalBackgroundColor, "00383838", "00CFCFCF"); #else initSetting(QSetting.AdditionalBackgroundColor , "00383838", "00C2C2C2"); #endif initSetting(HierarchySetting.AdditionalActiveColor, "FFFFFF80", "CF363636"); initSetting(HierarchySetting.AdditionalInactiveColor, "FF4F4F4F", "1E000000"); initSetting(HierarchySetting.AdditionalSpecialColor, "FF2CA8CA", "FF1D78D5"); } // DESTRUCTOR public void OnDestroy() { skinDependedSettings = null; defaultSettings = null; settingsObject = null; settingChangedHandlerList = null; instance = null; } // PUBLIC public T get(HierarchySetting setting) { return (T)settingsObject.get(getSettingName(setting)); } public Color getColor(HierarchySetting setting) { string stringColor = (string)settingsObject.get(getSettingName(setting)); return HierarchyColorUtils.fromString(stringColor); } public void setColor(HierarchySetting setting, Color color) { string stringColor = HierarchyColorUtils.toString(color); set(setting, stringColor); } public void set(HierarchySetting setting, T value, bool invokeChanger = true) { int settingId = (int)setting; settingsObject.set(getSettingName(setting), value); if (invokeChanger && settingChangedHandlerList.ContainsKey(settingId) && settingChangedHandlerList[settingId] != null) settingChangedHandlerList[settingId].Invoke(); EditorApplication.RepaintHierarchyWindow(); } public void addEventListener(HierarchySetting setting, SettingChangedHandler handler) { int settingId = (int)setting; if (!settingChangedHandlerList.ContainsKey(settingId)) settingChangedHandlerList.Add(settingId, null); if (settingChangedHandlerList[settingId] == null) settingChangedHandlerList[settingId] = handler; else settingChangedHandlerList[settingId] += handler; } public void removeEventListener(HierarchySetting setting, SettingChangedHandler handler) { int settingId = (int)setting; if (settingChangedHandlerList.ContainsKey(settingId) && settingChangedHandlerList[settingId] != null) settingChangedHandlerList[settingId] -= handler; } public void restore(HierarchySetting setting) { set(setting, defaultSettings[(int)setting]); } // PRIVATE private void initSetting(HierarchySetting setting, object defaultValueDark, object defaultValueLight) { skinDependedSettings.Add((int)setting); initSetting(setting, EditorGUIUtility.isProSkin ? defaultValueDark : defaultValueLight); } private void initSetting(HierarchySetting setting, object defaultValue) { string settingName = getSettingName(setting); defaultSettings.Add((int)setting, defaultValue); object value = settingsObject.get(settingName, defaultValue); if (value == null || value.GetType() != defaultValue.GetType()) { settingsObject.set(settingName, defaultValue); } } private string getSettingName(HierarchySetting setting) { int settingId = (int)setting; string settingName = PREFS_PREFIX; if (skinDependedSettings.Contains(settingId)) settingName += EditorGUIUtility.isProSkin ? PREFS_DARK : PREFS_LIGHT; settingName += setting.ToString("G"); return settingName.ToString(); } } } ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Data/HierarchySettings.cs.meta ================================================ fileFormatVersion: 2 guid: 22eaacdc264c5a84b9f790ff6b99896a timeCreated: 1477924880 licenseType: Store MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Data/HierarchySettingsObject.cs ================================================ using UnityEngine; using UnityEditor; using System; using System.Collections.Generic; namespace VirtueSky.Hierarchy.Data { [System.Serializable] class HierarchySettingsObject: ScriptableObject { [SerializeField] private List settingStringNames = new List(); [SerializeField] private List settingStringValues = new List(); [SerializeField] private List settingFloatNames = new List(); [SerializeField] private List settingFloatValues = new List(); [SerializeField] private List settingIntNames = new List(); [SerializeField] private List settingIntValues = new List(); [SerializeField] private List settingBoolNames = new List(); [SerializeField] private List settingBoolValues = new List(); public void clear() { settingStringNames.Clear(); settingStringValues.Clear(); settingFloatNames.Clear(); settingFloatValues.Clear(); settingIntNames.Clear(); settingIntValues.Clear(); settingBoolNames.Clear(); settingBoolValues.Clear(); } public void set(string settingName, object value) { if (value is bool) { settingBoolValues[settingBoolNames.IndexOf(settingName)] = (bool)value; } else if (value is string) { settingStringValues[settingStringNames.IndexOf(settingName)] = (string)value; } else if (value is float) { settingFloatValues[settingFloatNames.IndexOf(settingName)] = (float)value; } else if (value is int) { settingIntValues[settingIntNames.IndexOf(settingName)] = (int)value; } EditorUtility.SetDirty(this); } public object get(string settingName, object defaultValue) { if (defaultValue is bool) { int id = settingBoolNames.IndexOf(settingName); if (id == -1) { settingBoolNames.Add(settingName); settingBoolValues.Add((bool)defaultValue); return defaultValue; } else return settingBoolValues[id]; } else if (defaultValue is string) { int id = settingStringNames.IndexOf(settingName); if (id == -1) { settingStringNames.Add(settingName); settingStringValues.Add((string)defaultValue); return defaultValue; } else return settingStringValues[id]; } else if (defaultValue is float) { int id = settingFloatNames.IndexOf(settingName); if (id == -1) { settingFloatNames.Add(settingName); settingFloatValues.Add((float)defaultValue); return defaultValue; } else return settingFloatValues[id]; } else if (defaultValue is int) { int id = settingIntNames.IndexOf(settingName); if (id == -1) { settingIntNames.Add(settingName); settingIntValues.Add((int)defaultValue); return defaultValue; } else return settingIntValues[id]; } return null; } public object get(string settingName) { if (typeof(T) == typeof(bool)) { int id = settingBoolNames.IndexOf(settingName); if (id == -1) return null; else return settingBoolValues[id]; } else if (typeof(T) == typeof(string)) { int id = settingStringNames.IndexOf(settingName); if (id == -1) return null; else return settingStringValues[id]; } else if (typeof(T) == typeof(float)) { int id = settingFloatNames.IndexOf(settingName); if (id == -1) return null; else return settingFloatValues[id]; } else if (typeof(T) == typeof(int)) { int id = settingIntNames.IndexOf(settingName); if (id == -1) return null; else return settingIntValues[id]; } return null; } } } ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Data/HierarchySettingsObject.cs.meta ================================================ fileFormatVersion: 2 guid: b9eba1ecab4c43c41869985e270bbe09 timeCreated: 1478592157 licenseType: Store MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Data/QSettingsObjectAsset.asset ================================================ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: --- !u!114 &11400000 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 0} m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: b9eba1ecab4c43c41869985e270bbe09, type: 3} m_Name: QSettingsObjectAsset m_EditorClassIdentifier: settingStringNames: - QTools.QHierarchy_Light_TreeMapColor - QTools.QHierarchy_MonoBehaviourIconColor - QTools.QHierarchy_Light_SeparatorColor - QTools.QHierarchy_Light_SeparatorEvenRowShadingColor - QTools.QHierarchy_Light_SeparatorOddRowShadingColor - QTools.QHierarchy_ErrorIgnoreString - QTools.QHierarchy_Light_TagAndLayerTagLabelColor - QTools.QHierarchy_Light_TagAndLayerLayerLabelColor - QTools.QHierarchy_TagIconList - QTools.QHierarchy_LayerIconList - QTools.QHierarchy_Light_ChildrenCountLabelColor - QTools.QHierarchy_Light_VerticesAndTrianglesVerticesLabelColor - QTools.QHierarchy_Light_VerticesAndTrianglesTrianglesLabelColor - QTools.QHierarchy_ComponentsIgnore - QTools.QHierarchy_ComponentsOrder - QTools.QHierarchy_Light_AdditionalBackgroundColor - QTools.QHierarchy_Light_AdditionalActiveColor - QTools.QHierarchy_Light_AdditionalInactiveColor - QTools.QHierarchy_Light_AdditionalSpecialColor - QTools.QHierarchy_Dark_TreeMapColor - QTools.QHierarchy_Dark_SeparatorColor - QTools.QHierarchy_Dark_SeparatorEvenRowShadingColor - QTools.QHierarchy_Dark_SeparatorOddRowShadingColor - QTools.QHierarchy_Dark_TagAndLayerTagLabelColor - QTools.QHierarchy_Dark_TagAndLayerLayerLabelColor - QTools.QHierarchy_Dark_ChildrenCountLabelColor - QTools.QHierarchy_Dark_VerticesAndTrianglesVerticesLabelColor - QTools.QHierarchy_Dark_VerticesAndTrianglesTrianglesLabelColor - QTools.QHierarchy_Dark_AdditionalBackgroundColor - QTools.QHierarchy_Dark_AdditionalActiveColor - QTools.QHierarchy_Dark_AdditionalInactiveColor - QTools.QHierarchy_Dark_AdditionalSpecialColor settingStringValues: - 905D5D5D - A01B6DBB - 48666666 - 08000000 - 00FFFFFF - - FF333333 - FF333333 - - - FF333333 - FF333333 - FF333333 - - 0;1;2;3;4;5;6;7;8;9;10;11;12 - 00C2C2C2 - CF363636 - 1E000000 - FF1D78D5 - E028FF00 - FF303030 - 13000000 - 00000000 - FFE41616 - FF2B2E2C - FFCCCCCC - FFCCCCCC - FFCCCCCC - 00383838 - FFFFFF80 - FF4F4F4F - FF2CA8CA settingFloatNames: - QTools.QHierarchy_TagAndLayerSizeValuePercent - QTools.QHierarchy_TagAndLayerLabelAlpha settingFloatValues: - 0.25 - 0.35 settingIntNames: - QTools.QHierarchy_TagAndLayerSizeShowType - QTools.QHierarchy_TagAndLayerType - QTools.QHierarchy_TagAndLayerAligment - QTools.QHierarchy_TagAndLayerSizeValueType - QTools.QHierarchy_TagAndLayerSizeValuePixel - QTools.QHierarchy_TagAndLayerLabelSize - QTools.QHierarchy_GameObjectIconSize - QTools.QHierarchy_TagIconSize - QTools.QHierarchy_LayerIconSize - QTools.QHierarchy_ChildrenCountLabelSize - QTools.QHierarchy_VerticesAndTrianglesLabelSize - QTools.QHierarchy_ComponentsIconSize - QTools.QHierarchy_AdditionalIdentation settingIntValues: 000000000100000000000000000000003d0000000000000000000000000000000000000000000000000000000000000000000000 settingBoolNames: - QTools.QHierarchy_TreeMapShow - QTools.QHierarchy_TreeMapEnhanced - QTools.QHierarchy_TreeMapTransparentBackground - QTools.QHierarchy_MonoBehaviourIconShow - QTools.QHierarchy_MonoBehaviourIconShowDuringPlayMode - QTools.QHierarchy_MonoBehaviourIconIgnoreUnityMonobehaviour - QTools.QHierarchy_SeparatorShow - QTools.QHierarchy_SeparatorShowRowShading - QTools.QHierarchy_VisibilityShow - QTools.QHierarchy_VisibilityShowDuringPlayMode - QTools.QHierarchy_LockShow - QTools.QHierarchy_LockShowDuringPlayMode - QTools.QHierarchy_LockPreventSelectionOfLockedObjects - QTools.QHierarchy_StaticShow - QTools.QHierarchy_StaticShowDuringPlayMode - QTools.QHierarchy_ErrorShow - QTools.QHierarchy_ErrorShowDuringPlayMode - QTools.QHierarchy_ErrorShowIconOnParent - QTools.QHierarchy_ErrorShowScriptIsMissing - QTools.QHierarchy_ErrorShowReferenceIsNull - QTools.QHierarchy_ErrorShowReferenceIsMissing - QTools.QHierarchy_ErrorShowStringIsEmpty - QTools.QHierarchy_ErrorShowMissingEventMethod - QTools.QHierarchy_ErrorShowWhenTagOrLayerIsUndefined - QTools.QHierarchy_ErrorShowForDisabledComponents - QTools.QHierarchy_ErrorShowForDisabledGameObjects - QTools.QHierarchy_RendererShow - QTools.QHierarchy_RendererShowDuringPlayMode - QTools.QHierarchy_PrefabShow - QTools.QHierarchy_PrefabShowBreakedPrefabsOnly - QTools.QHierarchy_TagAndLayerShow - QTools.QHierarchy_TagAndLayerShowDuringPlayMode - QTools.QHierarchy_ColorShow - QTools.QHierarchy_ColorShowDuringPlayMode - QTools.QHierarchy_GameObjectIconShow - QTools.QHierarchy_GameObjectIconShowDuringPlayMode - QTools.QHierarchy_TagIconShow - QTools.QHierarchy_TagIconShowDuringPlayMode - QTools.QHierarchy_TagIconListFoldout - QTools.QHierarchy_LayerIconShow - QTools.QHierarchy_LayerIconShowDuringPlayMode - QTools.QHierarchy_LayerIconListFoldout - QTools.QHierarchy_ChildrenCountShow - QTools.QHierarchy_ChildrenCountShowDuringPlayMode - QTools.QHierarchy_VerticesAndTrianglesShow - QTools.QHierarchy_VerticesAndTrianglesShowDuringPlayMode - QTools.QHierarchy_VerticesAndTrianglesCalculateTotalCount - QTools.QHierarchy_VerticesAndTrianglesShowTriangles - QTools.QHierarchy_VerticesAndTrianglesShowVertices - QTools.QHierarchy_ComponentsShow - QTools.QHierarchy_ComponentsShowDuringPlayMode - QTools.QHierarchy_AdditionalShowObjectListContent - QTools.QHierarchy_AdditionalShowHiddenQHierarchyObjectList - QTools.QHierarchy_AdditionalHideIconsIfNotFit - QTools.QHierarchy_AdditionalShowModifierWarning settingBoolValues: 01010100010101010101010000000000000101010101010101010000000000010001000100010000010000010000010101010000010101 ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Data/QSettingsObjectAsset.asset.meta ================================================ fileFormatVersion: 2 guid: 3425b17243bd5c64393e28f9bd687fcb NativeFormatImporter: externalObjects: {} mainObjectFileID: 11400000 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Data.meta ================================================ fileFormatVersion: 2 guid: 288b7c4405cbf0a42a20f65be49ee978 folderAsset: yes timeCreated: 1515657177 licenseType: Store DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Helper/HierarchyColorPickerWindow.cs ================================================ using UnityEngine; using UnityEditor; using System.Collections; using System.Collections.Generic; using System.Text; using VirtueSky.Hierarchy.Data; namespace VirtueSky.Hierarchy.Helper { public delegate void HierarchyColorSelectedHandler(GameObject[] gameObjects, Color color); public delegate void HierarchyColorRemovedHandler(GameObject[] gameObjects); public class HierarchyColorPickerWindow: PopupWindowContent { // PRIVATE private GameObject[] gameObjects; private HierarchyColorSelectedHandler colorSelectedHandler; private HierarchyColorRemovedHandler colorRemovedHandler; private Texture2D colorPaletteTexture; private Rect paletteRect; // CONSTRUCTOR public HierarchyColorPickerWindow(GameObject[] gameObjects, HierarchyColorSelectedHandler colorSelectedHandler, HierarchyColorRemovedHandler colorRemovedHandler) { this.gameObjects = gameObjects; this.colorSelectedHandler = colorSelectedHandler; this.colorRemovedHandler = colorRemovedHandler; colorPaletteTexture = HierarchyResources.getInstance().getTexture(HierarchyTexture.HierarchyColorPalette); paletteRect = new Rect(0, 0, colorPaletteTexture.width, colorPaletteTexture.height); } // DESTRUCTOR public override void OnClose() { gameObjects = null; colorSelectedHandler = null; colorRemovedHandler = null; } // GUI public override Vector2 GetWindowSize() { return new Vector2(paletteRect.width, paletteRect.height); } public override void OnGUI(Rect rect) { GUI.DrawTexture(paletteRect, colorPaletteTexture); Vector2 mousePosition = Event.current.mousePosition; if (Event.current.isMouse && Event.current.button == 0 && Event.current.type == EventType.MouseUp && paletteRect.Contains(mousePosition)) { Event.current.Use(); if (mousePosition.x < 15 && mousePosition.y < 15) { colorRemovedHandler(gameObjects); } else { colorSelectedHandler(gameObjects, colorPaletteTexture.GetPixel((int)mousePosition.x, colorPaletteTexture.height - (int)mousePosition.y)); } this.editorWindow.Close(); } } } } ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Helper/HierarchyColorPickerWindow.cs.meta ================================================ fileFormatVersion: 2 guid: a7b2618f38024e943bb04bab606dc06e timeCreated: 1475051433 licenseType: Store MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Helper/HierarchyColorUtils.cs ================================================ using System; using UnityEngine; using UnityEditor; namespace VirtueSky.Hierarchy.Helper { public class HierarchyColorUtils { private static Color defaultColor = new Color(1.0f, 1.0f, 1.0f, 1.0f); public static void setDefaultColor(Color defaultColor) { HierarchyColorUtils.defaultColor = defaultColor; } public static void setColor(Color newColor) { GUI.color = newColor; } public static void setColor(Color newColor, float multiColor, float multiAlpha) { newColor.r *= multiColor; newColor.g *= multiColor; newColor.b *= multiColor; newColor.a *= multiAlpha; GUI.color = newColor; } public static void clearColor() { GUI.color = defaultColor; } public static Color fromString(string color) { return fromInt(Convert.ToUInt32(color,16)); } public static string toString(Color color) { uint intColor = toInt(color); return intColor.ToString("X8"); } public static Color fromInt(uint color) { return new Color(((color >> 16) & 0xFF) / 255.0f, ((color >> 8) & 0xFF) / 255.0f, ((color >> 0) & 0xFF) / 255.0f, ((color >> 24) & 0xFF) / 255.0f); } public static uint toInt(Color color) { return (uint)((byte)(color.r * 255) << 16) + (uint)((byte)(color.g * 255) << 8) + (uint)((byte)(color.b * 255) << 0) + (uint)((byte)(color.a * 255) << 24); } } } ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Helper/HierarchyColorUtils.cs.meta ================================================ fileFormatVersion: 2 guid: 70e4d942740a91e45b468c65bbeb78aa timeCreated: 1478071980 licenseType: Store MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Helper/HierarchyComponentsOrderList.cs ================================================ using UnityEditor; using UnityEngine; using System; using VirtueSky.Hierarchy.Data; using System.Text; namespace VirtueSky.Hierarchy.Helper { public class HierarchyComponentsOrderList { // PRIVATE private EditorWindow window; private Texture2D dragButton; private bool dragAndDrop = false; private float dragOffset; private int originalDragIndex; private Color backgroundColor; // CONSTRUCTOR public HierarchyComponentsOrderList (EditorWindow window) { this.window = window; dragButton = HierarchyResources.getInstance().getTexture(HierarchyTexture.HierarchyDragButton); backgroundColor = HierarchyResources.getInstance().getColor(HierarchyColor.BackgroundDark); } // PUBLIC public void draw(Rect rect, string[] componentIds) { Event currentEvent = Event.current; int currentMouseIndex = Mathf.Clamp(Mathf.RoundToInt((currentEvent.mousePosition.y - dragOffset - rect.y) / 18), 0, componentIds.Length - 1); if (dragAndDrop && currentEvent.type == EventType.MouseUp) { dragAndDrop = false; window.Repaint(); if (currentMouseIndex != originalDragIndex) { string newIconOrder = ""; for (int j = 0; j < componentIds.Length; j++) { if (j == currentMouseIndex) { if (j > originalDragIndex) { newIconOrder += componentIds[j] + ";"; newIconOrder += componentIds[originalDragIndex] + ";"; } else { newIconOrder += componentIds[originalDragIndex] + ";"; newIconOrder += componentIds[j] + ";"; } } else if (j != originalDragIndex) { newIconOrder += componentIds[j] + ";"; } } newIconOrder = newIconOrder.TrimEnd(';'); HierarchySettings.getInstance().set(HierarchySetting.ComponentsOrder, newIconOrder); componentIds = newIconOrder.Split(';'); } } else if (dragAndDrop && currentEvent.type == EventType.MouseDrag) { window.Repaint(); } for (int i = 0; i < componentIds.Length; i++) { HierarchyComponentEnum type = (HierarchyComponentEnum)int.Parse(componentIds[i]); Rect curRect = new Rect(rect.x, rect.y + 18 * i, rect.width, 16); if (!dragAndDrop && currentEvent.type == EventType.MouseDown && curRect.Contains(currentEvent.mousePosition)) { dragAndDrop = true; originalDragIndex = i; dragOffset = currentEvent.mousePosition.y - curRect.y; Event.current.Use(); } if (dragAndDrop) { if (originalDragIndex != i) { if (i < originalDragIndex && currentMouseIndex <= i) curRect.y += 18; else if (i > originalDragIndex && currentMouseIndex >= i) curRect.y -= 18; drawComponentLabel(curRect, type); } } else { drawComponentLabel(curRect, type); } } if (dragAndDrop) { float curY = currentEvent.mousePosition.y - dragOffset; curY = Mathf.Clamp(curY, rect.y, rect.y + rect.height - 16); drawComponentLabel(new Rect(rect.x, curY, rect.width, rect.height), (HierarchyComponentEnum)int.Parse(componentIds[originalDragIndex]), true); } } // PRIVATE private void drawComponentLabel(Rect rect, HierarchyComponentEnum type, bool withBackground = false) { if (withBackground) { EditorGUI.DrawRect(new Rect(rect.x, rect.y - 2, rect.width, 20), backgroundColor); } GUI.DrawTexture(new Rect(rect.x, rect.y - 2, 20, 20), dragButton); Rect labelRect = new Rect(rect.x + 31, rect.y, rect.width - 20, 16); labelRect.y -= (EditorGUIUtility.singleLineHeight - labelRect.height) * 0.5f; EditorGUI.LabelField(labelRect, getTextWithSpaces(type.ToString())); } private string getTextWithSpaces(string text) { StringBuilder newText = new StringBuilder(text.Length * 2); newText.Append(text[0]); for (int i = 1; i < text.Length; i++) { if (char.IsUpper(text[i]) && text[i - 1] != ' ') newText.Append(' '); newText.Append(text[i]); } newText.Replace(" Component", ""); return newText.ToString(); } } } ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Helper/HierarchyComponentsOrderList.cs.meta ================================================ fileFormatVersion: 2 guid: bd122316ceb5c1a469ec2d5e9ea9377f timeCreated: 1478011862 licenseType: Store MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Helper/HierarchyObjectListInspector.cs ================================================ using UnityEngine; using UnityEditor; using VirtueSky.Hierarchy.Data; namespace VirtueSky.Hierarchy.Helper { [CustomEditor(typeof(ObjectList))] public class HierarchyObjectListInspector : Editor { public override void OnInspectorGUI() { EditorGUILayout.HelpBox("\nThis is an auto created GameObject that managed by QHierarchy.\n\n" + "It stores references to some GameObjects in the current scene. This object will not be included in the application build.\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" + "This object can be hidden if you uncheck \"Show QHierarchy GameObject\" in the settings of the QHierarchy.\n" , MessageType.Info, true); if (HierarchySettings.getInstance().get(HierarchySetting.AdditionalShowObjectListContent)) { if (GUI.Button(EditorGUILayout.GetControlRect(GUILayout.ExpandWidth(true), GUILayout.Height(20)), "Hide content")) { HierarchySettings.getInstance().set(HierarchySetting.AdditionalShowObjectListContent, false); } base.OnInspectorGUI(); } else { if (GUI.Button(EditorGUILayout.GetControlRect(GUILayout.ExpandWidth(true), GUILayout.Height(20)), "Show content")) { HierarchySettings.getInstance().set(HierarchySetting.AdditionalShowObjectListContent, true); } } } } } ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Helper/HierarchyObjectListInspector.cs.meta ================================================ fileFormatVersion: 2 guid: 1182108d9515cea4aa965206552f3c33 timeCreated: 1475228494 licenseType: Store MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Helper/HierarchyObjectListManager.cs ================================================ using System; using System.Collections.Generic; using UnityEngine; using UnityEditor; using VirtueSky.Hierarchy.Data; #if UNITY_5_3_OR_NEWER using UnityEngine.SceneManagement; using UnityEditor.SceneManagement; #endif namespace VirtueSky.Hierarchy.Helper { public class HierarchyObjectListManager { // CONST private const string HierarchyObjectListName = "QHierarchyObjectList"; // SINGLETON private static HierarchyObjectListManager instance; public static HierarchyObjectListManager getInstance() { if (instance == null) instance = new HierarchyObjectListManager(); return instance; } // PRIVATE private bool showObjectList; private bool preventSelectionOfLockedObjects; private bool preventSelectionOfLockedObjectsDuringPlayMode; private GameObject lastSelectionGameObject = null; private int lastSelectionCount = 0; // CONSTRUCTOR private HierarchyObjectListManager() { HierarchySettings.getInstance().addEventListener(HierarchySetting.AdditionalShowHiddenQHierarchyObjectList , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.LockPreventSelectionOfLockedObjects, settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.LockShow , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.LockShowDuringPlayMode, settingsChanged); settingsChanged(); } private void settingsChanged() { showObjectList = HierarchySettings.getInstance().get(HierarchySetting.AdditionalShowHiddenQHierarchyObjectList); preventSelectionOfLockedObjects = HierarchySettings.getInstance().get(HierarchySetting.LockShow) && HierarchySettings.getInstance().get(HierarchySetting.LockPreventSelectionOfLockedObjects); preventSelectionOfLockedObjectsDuringPlayMode = preventSelectionOfLockedObjects && HierarchySettings.getInstance().get(HierarchySetting.LockShowDuringPlayMode); } private bool isSelectionChanged() { if (lastSelectionGameObject != Selection.activeGameObject || lastSelectionCount != Selection.gameObjects.Length) { lastSelectionGameObject = Selection.activeGameObject; lastSelectionCount = Selection.gameObjects.Length; return true; } return false; } public void validate() { ObjectList.instances.RemoveAll(item => item == null); foreach (ObjectList objectList in ObjectList.instances) objectList.checkIntegrity(); #if UNITY_5_3_OR_NEWER objectListDictionary.Clear(); foreach (ObjectList objectList in ObjectList.instances) objectListDictionary.Add(objectList.gameObject.scene, objectList); #endif } #if UNITY_5_3_OR_NEWER private Dictionary objectListDictionary = new Dictionary(); private Scene lastActiveScene; private int lastSceneCount = 0; public void update() { try { List objectListList = ObjectList.instances; int objectListCount = objectListList.Count; if (objectListCount > 0) { for (int i = objectListCount - 1; i >= 0; i--) { ObjectList objectList = objectListList[i]; Scene objectListScene = objectList.gameObject.scene; if (objectListDictionary.ContainsKey(objectListScene) && objectListDictionary[objectListScene] == null) objectListDictionary.Remove(objectListScene); if (objectListDictionary.ContainsKey(objectListScene)) { if (objectListDictionary[objectListScene] != objectList) { objectListDictionary[objectListScene].merge(objectList); GameObject.DestroyImmediate(objectList.gameObject); } } else { objectListDictionary.Add(objectListScene, objectList); } } foreach (KeyValuePair objectListKeyValue in objectListDictionary) { ObjectList objectList = objectListKeyValue.Value; setupObjectList(objectList); if (( showObjectList && ((objectList.gameObject.hideFlags & HideFlags.HideInHierarchy) > 0)) || (!showObjectList && ((objectList.gameObject.hideFlags & HideFlags.HideInHierarchy) == 0))) { objectList.gameObject.hideFlags ^= HideFlags.HideInHierarchy; EditorApplication.DirtyHierarchyWindowSorting(); } } if ((!Application.isPlaying && preventSelectionOfLockedObjects) || ((Application.isPlaying && preventSelectionOfLockedObjectsDuringPlayMode)) && isSelectionChanged()) { GameObject[] selections = Selection.gameObjects; List actual = new List(selections.Length); bool found = false; for (int i = selections.Length - 1; i >= 0; i--) { GameObject gameObject = selections[i]; if (objectListDictionary.ContainsKey(gameObject.scene)) { bool isLock = objectListDictionary[gameObject.scene].lockedObjects.Contains(selections[i]); if (!isLock) actual.Add(selections[i]); else found = true; } } if (found) Selection.objects = actual.ToArray(); } lastActiveScene = EditorSceneManager.GetActiveScene(); lastSceneCount = SceneManager.loadedSceneCount; } } catch { } } public ObjectList getObjectList(GameObject gameObject, bool createIfNotExist = true) { ObjectList objectList = null; objectListDictionary.TryGetValue(gameObject.scene, out objectList); if (objectList == null && createIfNotExist) { objectList = createObjectList(gameObject); if (gameObject.scene != objectList.gameObject.scene) EditorSceneManager.MoveGameObjectToScene(objectList.gameObject, gameObject.scene); objectListDictionary.Add(gameObject.scene, objectList); } return objectList; } public bool isSceneChanged() { if (lastActiveScene != EditorSceneManager.GetActiveScene() || lastSceneCount != SceneManager.loadedSceneCount) return true; else return false; } #else public void update() { try { List objectListList = QObjectList.instances; int objectListCount = objectListList.Count; if (objectListCount > 0) { if (objectListCount > 1) { for (int i = objectListCount - 1; i > 0; i--) { objectListList[0].merge(objectListList[i]); GameObject.DestroyImmediate(objectListList[i].gameObject); } } QObjectList objectList = QObjectList.instances[0]; setupObjectList(objectList); if (( showObjectList && ((objectList.gameObject.hideFlags & HideFlags.HideInHierarchy) > 0)) || (!showObjectList && ((objectList.gameObject.hideFlags & HideFlags.HideInHierarchy) == 0))) { objectList.gameObject.hideFlags ^= HideFlags.HideInHierarchy; EditorApplication.DirtyHierarchyWindowSorting(); } if ((!Application.isPlaying && preventSelectionOfLockedObjects) || ((Application.isPlaying && preventSelectionOfLockedObjectsDuringPlayMode)) && isSelectionChanged()) { GameObject[] selections = Selection.gameObjects; List actual = new List(selections.Length); bool found = false; for (int i = selections.Length - 1; i >= 0; i--) { GameObject gameObject = selections[i]; bool isLock = objectList.lockedObjects.Contains(gameObject); if (!isLock) actual.Add(selections[i]); else found = true; } if (found) Selection.objects = actual.ToArray(); } } } catch { } } public QObjectList getObjectList(GameObject gameObject, bool createIfNotExists = false) { List objectListList = QObjectList.instances; int objectListCount = objectListList.Count; if (objectListCount != 1) { if (objectListCount == 0) { if (createIfNotExists) { createObjectList(gameObject); } else { return null; } } } return QObjectList.instances[0]; } #endif private ObjectList createObjectList(GameObject gameObject) { GameObject gameObjectList = new GameObject(); gameObjectList.name = HierarchyObjectListName; ObjectList objectList = gameObjectList.AddComponent(); setupObjectList(objectList); return objectList; } private void setupObjectList(ObjectList objectList) { if (objectList.tag == "EditorOnly") objectList.tag = "Untagged"; MonoScript monoScript = MonoScript.FromMonoBehaviour(objectList); if (MonoImporter.GetExecutionOrder(monoScript) != -10000) MonoImporter.SetExecutionOrder(monoScript, -10000); } } } ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Helper/HierarchyObjectListManager.cs.meta ================================================ fileFormatVersion: 2 guid: dac6048cde5fd4d4399d16cc2ffba265 timeCreated: 1475228494 licenseType: Store MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/Helper.meta ================================================ fileFormatVersion: 2 guid: 4874c05321df8604d93643d0c4918324 folderAsset: yes timeCreated: 1515657177 licenseType: Store DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/QHierarchyInitializer.cs ================================================ using UnityEngine; using UnityEditor; using System; using System.Collections.Generic; using VirtueSky.Hierarchy.Data; using VirtueSky.Hierarchy; using UnityEditor.Callbacks; using VirtueSky.Hierarchy.Helper; using VirtueSky.Hierarchy.phierarchy; namespace VirtueSky.Hierarchy { [InitializeOnLoad] public class QHierarchyInitializer { private static VHierarchy hierarchy; static QHierarchyInitializer() { EditorApplication.update -= update; EditorApplication.update += update; EditorApplication.hierarchyWindowItemOnGUI -= hierarchyWindowItemOnGUIHandler; EditorApplication.hierarchyWindowItemOnGUI += hierarchyWindowItemOnGUIHandler; EditorApplication.hierarchyChanged -= hierarchyWindowChanged; EditorApplication.hierarchyChanged += hierarchyWindowChanged; Undo.undoRedoPerformed -= undoRedoPerformed; Undo.undoRedoPerformed += undoRedoPerformed; } static void undoRedoPerformed() { EditorApplication.RepaintHierarchyWindow(); } static void init() { hierarchy = new VHierarchy(); } static void update() { if (hierarchy == null) init(); HierarchyObjectListManager.getInstance().update(); } static void hierarchyWindowItemOnGUIHandler(int instanceId, Rect selectionRect) { if (hierarchy == null) init(); hierarchy.hierarchyWindowItemOnGUIHandler(instanceId, selectionRect); } static void hierarchyWindowChanged() { if (hierarchy == null) init(); HierarchyObjectListManager.getInstance().validate(); } } } ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/QHierarchyInitializer.cs.meta ================================================ fileFormatVersion: 2 guid: 91dfc025140434846819647cecf3bd95 timeCreated: 1474889436 licenseType: Store MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/VHierarchy/HierarchySettingsWindow.cs ================================================ using UnityEngine; using UnityEditor; using System.Collections; using System.Collections.Generic; using System.Text; using VirtueSky.Hierarchy.Data; using System; using VirtueSky.Hierarchy.Helper; using VirtueSky.Hierarchy.HComponent; using VirtueSky.Inspector; namespace VirtueSky.Hierarchy.phierarchy { public class HierarchySettingsWindow : EditorWindow { // STATIC //[MenuItem ("Tools/QHierarchy/Settings")] // public static void ShowWindow() // { // EditorWindow window = EditorWindow.GetWindow(typeof(QHierarchySettingsWindow)); // window.minSize = new Vector2(350, 50); // // #if UNITY_4_6 || UNITY_4_7 || UNITY_5_0 // window.title = "QHierarchy"; // #else // window.titleContent = new GUIContent("QHierarchy"); // #endif // } // // // PRIVATE // private bool inited = false; // private Rect lastRect; // private bool isProSkin; // private int indentLevel; // private Texture2D checkBoxChecked; // private Texture2D checkBoxUnchecked; // private Texture2D restoreButtonTexture; // private Vector2 scrollPosition = new Vector2(); // private Color separatorColor; // private Color yellowColor; // private float totalWidth; // private QComponentsOrderList componentsOrderList; // // // INIT // private void init() // { // inited = true; // isProSkin = EditorGUIUtility.isProSkin; // separatorColor = // isProSkin ? new Color(0.18f, 0.18f, 0.18f) : new Color(0.59f, 0.59f, 0.59f); // yellowColor = // isProSkin ? new Color(1.00f, 0.90f, 0.40f) : new Color(0.31f, 0.31f, 0.31f); // checkBoxChecked = QResources.getInstance().getTexture(QTexture.QCheckBoxChecked); // checkBoxUnchecked = QResources.getInstance().getTexture(QTexture.QCheckBoxUnchecked); // restoreButtonTexture = QResources.getInstance().getTexture(QTexture.QRestoreButton); // componentsOrderList = new QComponentsOrderList(this); // } // // // GUI // public void OnGUI() // { // EditorGUI.DrawRect(new Rect(0, 0, position.width, position.height), // GameDataEditor.ColorBackgroundRectWindowSunflower.ToColor()); // GUI.contentColor = GameDataEditor.ColorTextContentWindowSunflower.ToColor(); // GUI.backgroundColor = GameDataEditor.ColorContentWindowSunflower.ToColor(); // if (!inited || isProSkin != EditorGUIUtility.isProSkin) // init(); // // indentLevel = 8; // scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition); // { // Rect targetRect = EditorGUILayout.GetControlRect(GUILayout.Height(0)); // if (Event.current.type == EventType.Repaint) totalWidth = targetRect.width + 8; // // this.lastRect = new Rect(0, 1, 0, 0); // // // COMPONENTS // drawSection("COMPONENTS SETTINGS"); // float sectionStartY = lastRect.y + lastRect.height; // // drawTreeMapComponentSettings(); // drawSeparator(); // drawMonoBehaviourIconComponentSettings(); // drawSeparator(); // drawSeparatorComponentSettings(); // drawSeparator(); // drawVisibilityComponentSettings(); // drawSeparator(); // drawLockComponentSettings(); // drawSeparator(); // drawStaticComponentSettings(); // drawSeparator(); // drawErrorComponentSettings(); // drawSeparator(); // drawRendererComponentSettings(); // drawSeparator(); // drawPrefabComponentSettings(); // drawSeparator(); // drawTagLayerComponentSettings(); // drawSeparator(); // drawColorComponentSettings(); // drawSeparator(); // drawGameObjectIconComponentSettings(); // drawSeparator(); // drawTagIconComponentSettings(); // drawSeparator(); // drawLayerIconComponentSettings(); // drawSeparator(); // drawChildrenCountComponentSettings(); // drawSeparator(); // drawVerticesAndTrianglesCountComponentSettings(); // drawSeparator(); // drawComponentsComponentSettings(); // drawLeftLine(sectionStartY, lastRect.y + lastRect.height, separatorColor); // // // ORDER // drawSection("ORDER OF COMPONENTS"); // sectionStartY = lastRect.y + lastRect.height; // drawSpace(8); // drawOrderSettings(); // drawSpace(6); // drawLeftLine(sectionStartY, lastRect.y + lastRect.height, separatorColor); // // // ADDITIONAL // drawSection("ADDITIONAL SETTINGS"); // sectionStartY = lastRect.y + lastRect.height; // drawSpace(3); // drawAdditionalSettings(); // drawLeftLine(sectionStartY, lastRect.y + lastRect.height + 4, separatorColor); // // indentLevel -= 1; // } // // EditorGUILayout.EndScrollView(); // } // // // COMPONENTS // private void drawTreeMapComponentSettings() // { // if (drawComponentCheckBox("Hierarchy Tree", QSetting.TreeMapShow)) // { // Rect rect = getControlRect(0, 0); // if (drawRestore()) // { // QSettings.getInstance().restore(QSetting.TreeMapColor); // QSettings.getInstance().restore(QSetting.TreeMapEnhanced); // QSettings.getInstance().restore(QSetting.TreeMapTransparentBackground); // } // // drawBackground(rect.x, rect.y, rect.width, 18 * 3 + 5); // drawSpace(4); // drawColorPicker("Tree color", QSetting.TreeMapColor); // drawCheckBoxRight("Transparent background", QSetting.TreeMapTransparentBackground); // drawCheckBoxRight("Enhanced (\"Transform Sort\" only)", QSetting.TreeMapEnhanced); // drawSpace(1); // } // } // // private void drawMonoBehaviourIconComponentSettings() // { // if (drawComponentCheckBox("MonoBehaviour Icon", QSetting.MonoBehaviourIconShow)) // { // Rect rect = getControlRect(0, 0); // if (drawRestore()) // { // QSettings.getInstance().restore(QSetting.MonoBehaviourIconShowDuringPlayMode); // QSettings.getInstance().restore(QSetting.MonoBehaviourIconColor); // QSettings.getInstance() // .restore(QSetting.MonoBehaviourIconIgnoreUnityMonobehaviour); // } // // drawBackground(rect.x, rect.y, rect.width, 18 * 3 + 5); // drawSpace(4); // drawCheckBoxRight("Show component during play mode", // QSetting.MonoBehaviourIconShowDuringPlayMode); // drawColorPicker("Icon color", QSetting.MonoBehaviourIconColor); // drawCheckBoxRight("Ignore Unity MonoBehaviours", // QSetting.MonoBehaviourIconIgnoreUnityMonobehaviour); // drawSpace(1); // } // } // // private void drawSeparatorComponentSettings() // { // if (drawComponentCheckBox("Separator", QSetting.SeparatorShow)) // { // Rect rect = getControlRect(0, 0); // if (drawRestore()) // { // QSettings.getInstance().restore(QSetting.SeparatorColor); // QSettings.getInstance().restore(QSetting.SeparatorShowRowShading); // QSettings.getInstance().restore(QSetting.SeparatorOddRowShadingColor); // QSettings.getInstance().restore(QSetting.SeparatorEvenRowShadingColor); // } // // bool rowShading = // QSettings.getInstance().get(QSetting.SeparatorShowRowShading); // // drawBackground(rect.x, rect.y, rect.width, 18 * (rowShading ? 4 : 2) + 5); // drawSpace(4); // drawColorPicker("Separator Color", QSetting.SeparatorColor); // drawCheckBoxRight("Row shading", QSetting.SeparatorShowRowShading); // if (rowShading) // { // drawColorPicker("Even row shading color", // QSetting.SeparatorEvenRowShadingColor); // drawColorPicker("Odd row shading color", QSetting.SeparatorOddRowShadingColor); // } // // drawSpace(1); // } // } // // private void drawVisibilityComponentSettings() // { // if (drawComponentCheckBox("Visibility", QSetting.VisibilityShow)) // { // Rect rect = getControlRect(0, 0); // if (drawRestore()) // { // QSettings.getInstance().restore(QSetting.VisibilityShowDuringPlayMode); // } // // drawBackground(rect.x, rect.y, rect.width, 18 + 5); // drawSpace(4); // drawCheckBoxRight("Show component during play mode", // QSetting.VisibilityShowDuringPlayMode); // drawSpace(1); // } // } // // private void drawLockComponentSettings() // { // if (drawComponentCheckBox("Lock", QSetting.LockShow)) // { // Rect rect = getControlRect(0, 0); // if (drawRestore()) // { // QSettings.getInstance().restore(QSetting.LockShowDuringPlayMode); // QSettings.getInstance().restore(QSetting.LockPreventSelectionOfLockedObjects); // } // // drawBackground(rect.x, rect.y, rect.width, 18 * 2 + 5); // drawSpace(4); // drawCheckBoxRight("Show component during play mode", // QSetting.LockShowDuringPlayMode); // drawCheckBoxRight("Prevent selection of locked objects", // QSetting.LockPreventSelectionOfLockedObjects); // drawSpace(1); // } // } // // private void drawStaticComponentSettings() // { // if (drawComponentCheckBox("Static", QSetting.StaticShow)) // { // Rect rect = getControlRect(0, 0); // if (drawRestore()) // { // QSettings.getInstance().restore(QSetting.StaticShowDuringPlayMode); // } // // drawBackground(rect.x, rect.y, rect.width, 18 + 5); // drawSpace(4); // drawCheckBoxRight("Show component during play mode", // QSetting.StaticShowDuringPlayMode); // drawSpace(1); // } // } // // private void drawErrorComponentSettings() // { // if (drawComponentCheckBox("Error", QSetting.ErrorShow)) // { // Rect rect = getControlRect(0, 0); // if (drawRestore()) // { // QSettings.getInstance().restore(QSetting.ErrorShowDuringPlayMode); // QSettings.getInstance().restore(QSetting.ErrorShowIconOnParent); // QSettings.getInstance().restore(QSetting.ErrorShowForDisabledComponents); // QSettings.getInstance().restore(QSetting.ErrorShowForDisabledGameObjects); // QSettings.getInstance().restore(QSetting.ErrorShowScriptIsMissing); // QSettings.getInstance().restore(QSetting.ErrorShowReferenceIsMissing); // QSettings.getInstance().restore(QSetting.ErrorShowReferenceIsNull); // QSettings.getInstance().restore(QSetting.ErrorShowStringIsEmpty); // QSettings.getInstance().restore(QSetting.ErrorShowMissingEventMethod); // QSettings.getInstance().restore(QSetting.ErrorShowWhenTagOrLayerIsUndefined); // QSettings.getInstance().restore(QSetting.ErrorIgnoreString); // } // // drawBackground(rect.x, rect.y, rect.width, 18 * 12 + 5); // drawSpace(4); // drawCheckBoxRight("Show component during play mode", // QSetting.ErrorShowDuringPlayMode); // drawCheckBoxRight("Show error icon up of hierarchy (very slow)", // QSetting.ErrorShowIconOnParent); // drawCheckBoxRight("Show error icon for disabled components", // QSetting.ErrorShowForDisabledComponents); // drawCheckBoxRight("Show error icon for disabled GameObjects", // QSetting.ErrorShowForDisabledGameObjects); // drawLabel("Show error icon for the following:"); // indentLevel += 16; // drawCheckBoxRight("- script is missing", QSetting.ErrorShowScriptIsMissing); // drawCheckBoxRight("- reference is missing", QSetting.ErrorShowReferenceIsMissing); // drawCheckBoxRight("- reference is null", QSetting.ErrorShowReferenceIsNull); // drawCheckBoxRight("- string is empty", QSetting.ErrorShowStringIsEmpty); // drawCheckBoxRight("- callback of event is missing (very slow)", // QSetting.ErrorShowMissingEventMethod); // drawCheckBoxRight("- tag or layer is undefined", // QSetting.ErrorShowWhenTagOrLayerIsUndefined); // indentLevel -= 16; // drawTextField("Ignore packages/classes", QSetting.ErrorIgnoreString); // drawSpace(1); // } // } // // private void drawRendererComponentSettings() // { // if (drawComponentCheckBox("Renderer", QSetting.RendererShow)) // { // Rect rect = getControlRect(0, 0); // if (drawRestore()) // { // QSettings.getInstance().restore(QSetting.RendererShowDuringPlayMode); // } // // drawBackground(rect.x, rect.y, rect.width, 18 + 5); // drawSpace(4); // drawCheckBoxRight("Show component during play mode", // QSetting.RendererShowDuringPlayMode); // drawSpace(1); // } // } // // private void drawPrefabComponentSettings() // { // if (drawComponentCheckBox("Prefab", QSetting.PrefabShow)) // { // Rect rect = getControlRect(0, 0); // if (drawRestore()) // { // QSettings.getInstance().restore(QSetting.PrefabShowBreakedPrefabsOnly); // } // // drawBackground(rect.x, rect.y, rect.width, 18 + 5); // drawSpace(4); // drawCheckBoxRight("Show icon for broken prefabs only", // QSetting.PrefabShowBreakedPrefabsOnly); // drawSpace(1); // } // } // // private void drawTagLayerComponentSettings() // { // if (drawComponentCheckBox("Tag And Layer", QSetting.TagAndLayerShow)) // { // Rect rect = getControlRect(0, 0); // if (drawRestore()) // { // QSettings.getInstance().restore(QSetting.TagAndLayerShowDuringPlayMode); // QSettings.getInstance().restore(QSetting.TagAndLayerSizeShowType); // QSettings.getInstance().restore(QSetting.TagAndLayerType); // QSettings.getInstance().restore(QSetting.TagAndLayerSizeValueType); // QSettings.getInstance().restore(QSetting.TagAndLayerSizeValuePixel); // QSettings.getInstance().restore(QSetting.TagAndLayerSizeValuePercent); // QSettings.getInstance().restore(QSetting.TagAndLayerAligment); // QSettings.getInstance().restore(QSetting.TagAndLayerLabelSize); // QSettings.getInstance().restore(QSetting.TagAndLayerLabelAlpha); // QSettings.getInstance().restore(QSetting.TagAndLayerTagLabelColor); // QSettings.getInstance().restore(QSetting.TagAndLayerLayerLabelColor); // } // // drawBackground(rect.x, rect.y, rect.width, 18 * 10 + 5); // drawSpace(4); // drawCheckBoxRight("Show component during play mode", // QSetting.TagAndLayerShowDuringPlayMode); // drawEnum("Show", QSetting.TagAndLayerSizeShowType, // typeof(QHierarchyTagAndLayerShowType)); // drawEnum("Show tag and layer", QSetting.TagAndLayerType, // typeof(QHierarchyTagAndLayerType)); // // QHierarchyTagAndLayerSizeType newTagAndLayerSizeValueType = // (QHierarchyTagAndLayerSizeType)drawEnum("Unit of width", // QSetting.TagAndLayerSizeValueType, typeof(QHierarchyTagAndLayerSizeType)); // // if (newTagAndLayerSizeValueType == QHierarchyTagAndLayerSizeType.Pixel) // drawIntSlider("Width in pixels", QSetting.TagAndLayerSizeValuePixel, 5, 250); // else // drawFloatSlider("Percentage width", QSetting.TagAndLayerSizeValuePercent, 0, // 0.5f); // // drawEnum("Alignment", QSetting.TagAndLayerAligment, // typeof(QHierarchyTagAndLayerAligment)); // drawEnum("Label size", QSetting.TagAndLayerLabelSize, // typeof(QHierarchyTagAndLayerLabelSize)); // drawFloatSlider("Label alpha if default", QSetting.TagAndLayerLabelAlpha, 0, 1.0f); // drawColorPicker("Tag label color", QSetting.TagAndLayerTagLabelColor); // drawColorPicker("Layer label color", QSetting.TagAndLayerLayerLabelColor); // drawSpace(1); // } // } // // private void drawColorComponentSettings() // { // if (drawComponentCheckBox("Color", QSetting.ColorShow)) // { // Rect rect = getControlRect(0, 0); // if (drawRestore()) // { // QSettings.getInstance().restore(QSetting.ColorShowDuringPlayMode); // } // // drawBackground(rect.x, rect.y, rect.width, 18 + 5); // drawSpace(4); // drawCheckBoxRight("Show component during play mode", // QSetting.ColorShowDuringPlayMode); // drawSpace(1); // } // } // // private void drawGameObjectIconComponentSettings() // { // if (drawComponentCheckBox("GameObject Icon", QSetting.GameObjectIconShow)) // { // Rect rect = getControlRect(0, 0); // if (drawRestore()) // { // QSettings.getInstance().restore(QSetting.GameObjectIconShowDuringPlayMode); // QSettings.getInstance().restore(QSetting.GameObjectIconSize); // } // // drawBackground(rect.x, rect.y, rect.width, 18 * 2 + 5); // drawSpace(4); // drawCheckBoxRight("Show component during play mode", // QSetting.GameObjectIconShowDuringPlayMode); // drawEnum("Icon size", QSetting.GameObjectIconSize, typeof(QHierarchySizeAll)); // drawSpace(1); // } // } // // private void drawTagIconComponentSettings() // { // if (drawComponentCheckBox("Tag Icon", QSetting.TagIconShow)) // { // string[] tags = UnityEditorInternal.InternalEditorUtility.tags; // // bool showTagIconList = // QSettings.getInstance().get(QSetting.TagIconListFoldout); // // Rect rect = getControlRect(0, 0); // if (drawRestore()) // { // QSettings.getInstance().restore(QSetting.TagIconShowDuringPlayMode); // QSettings.getInstance().restore(QSetting.TagIconSize); // } // // drawBackground(rect.x, rect.y, rect.width, // 18 * 3 + (showTagIconList ? 18 * tags.Length : 0) + 4 + 5); // // drawSpace(4); // drawCheckBoxRight("Show component during play mode", // QSetting.TagIconShowDuringPlayMode); // drawEnum("Icon size", QSetting.TagIconSize, typeof(QHierarchySizeAll)); // if (drawFoldout("Tag icon list", QSetting.TagIconListFoldout)) // { // List tagTextureList = QTagTexture.loadTagTextureList(); // // bool changed = false; // for (int i = 0; i < tags.Length; i++) // { // string tag = tags[i]; // QTagTexture tagTexture = tagTextureList.Find(t => t.tag == tag); // Texture2D newTexture = (Texture2D)EditorGUI.ObjectField( // getControlRect(0, 16, 34 + 16, 6), // tag, tagTexture == null ? null : tagTexture.texture, typeof(Texture2D), // false); // if (newTexture != null && tagTexture == null) // { // QTagTexture newTagTexture = new QTagTexture(tag, newTexture); // tagTextureList.Add(newTagTexture); // // changed = true; // } // else if (newTexture == null && tagTexture != null) // { // tagTextureList.Remove(tagTexture); // changed = true; // } // else if (tagTexture != null && tagTexture.texture != newTexture) // { // tagTexture.texture = newTexture; // changed = true; // } // // drawSpace(i == tags.Length - 1 ? 2 : 2); // } // // if (changed) // { // QTagTexture.saveTagTextureList(QSetting.TagIconList, tagTextureList); // EditorApplication.RepaintHierarchyWindow(); // } // } // // drawSpace(1); // } // } // // private void drawLayerIconComponentSettings() // { // if (drawComponentCheckBox("Layer Icon", QSetting.LayerIconShow)) // { // string[] layers = UnityEditorInternal.InternalEditorUtility.layers; // // bool showLayerIconList = // QSettings.getInstance().get(QSetting.LayerIconListFoldout); // // Rect rect = getControlRect(0, 0); // if (drawRestore()) // { // QSettings.getInstance().restore(QSetting.LayerIconShowDuringPlayMode); // QSettings.getInstance().restore(QSetting.LayerIconSize); // } // // drawBackground(rect.x, rect.y, rect.width, // 18 * 3 + (showLayerIconList ? 18 * layers.Length : 0) + 4 + 5); // // drawSpace(4); // drawCheckBoxRight("Show component during play mode", // QSetting.LayerIconShowDuringPlayMode); // drawEnum("Icon size", QSetting.LayerIconSize, typeof(QHierarchySizeAll)); // if (drawFoldout("Layer icon list", QSetting.LayerIconListFoldout)) // { // List layerTextureList = QLayerTexture.loadLayerTextureList(); // // bool changed = false; // for (int i = 0; i < layers.Length; i++) // { // string layer = layers[i]; // QLayerTexture layerTexture = layerTextureList.Find(t => t.layer == layer); // Texture2D newTexture = (Texture2D)EditorGUI.ObjectField( // getControlRect(0, 16, 34 + 16, 6), // layer, layerTexture == null ? null : layerTexture.texture, // typeof(Texture2D), false); // if (newTexture != null && layerTexture == null) // { // QLayerTexture newLayerTexture = new QLayerTexture(layer, newTexture); // layerTextureList.Add(newLayerTexture); // // changed = true; // } // else if (newTexture == null && layerTexture != null) // { // layerTextureList.Remove(layerTexture); // changed = true; // } // else if (layerTexture != null && layerTexture.texture != newTexture) // { // layerTexture.texture = newTexture; // changed = true; // } // // drawSpace(i == layers.Length - 1 ? 2 : 2); // } // // if (changed) // { // QLayerTexture.saveLayerTextureList(QSetting.LayerIconList, // layerTextureList); // EditorApplication.RepaintHierarchyWindow(); // } // } // // drawSpace(1); // } // } // // private void drawChildrenCountComponentSettings() // { // if (drawComponentCheckBox("Children Count", QSetting.ChildrenCountShow)) // { // Rect rect = getControlRect(0, 0); // if (drawRestore()) // { // QSettings.getInstance().restore(QSetting.ChildrenCountShowDuringPlayMode); // QSettings.getInstance().restore(QSetting.ChildrenCountLabelSize); // QSettings.getInstance().restore(QSetting.ChildrenCountLabelColor); // } // // drawBackground(rect.x, rect.y, rect.width, 18 * 3 + 5); // drawSpace(4); // drawCheckBoxRight("Show component during play mode", // QSetting.ChildrenCountShowDuringPlayMode); // drawEnum("Label size", QSetting.ChildrenCountLabelSize, typeof(QHierarchySize)); // drawColorPicker("Label color", QSetting.ChildrenCountLabelColor); // drawSpace(1); // } // } // // private void drawVerticesAndTrianglesCountComponentSettings() // { // if (drawComponentCheckBox("Vertices And Triangles Count", // QSetting.VerticesAndTrianglesShow)) // { // Rect rect = getControlRect(0, 0); // if (drawRestore()) // { // QSettings.getInstance() // .restore(QSetting.VerticesAndTrianglesShowDuringPlayMode); // QSettings.getInstance().restore(QSetting.VerticesAndTrianglesShowVertices); // QSettings.getInstance().restore(QSetting.VerticesAndTrianglesShowTriangles); // QSettings.getInstance() // .restore(QSetting.VerticesAndTrianglesCalculateTotalCount); // QSettings.getInstance().restore(QSetting.VerticesAndTrianglesLabelSize); // QSettings.getInstance() // .restore(QSetting.VerticesAndTrianglesVerticesLabelColor); // QSettings.getInstance() // .restore(QSetting.VerticesAndTrianglesTrianglesLabelColor); // } // // drawBackground(rect.x, rect.y, rect.width, 18 * 7 + 5); // drawSpace(4); // drawCheckBoxRight("Show component during play mode", // QSetting.VerticesAndTrianglesShowDuringPlayMode); // if (drawCheckBoxRight("Show vertices count", // QSetting.VerticesAndTrianglesShowVertices)) // { // if (QSettings.getInstance() // .get(QSetting.VerticesAndTrianglesShowVertices) == false && // QSettings.getInstance() // .get(QSetting.VerticesAndTrianglesShowTriangles) == false) // QSettings.getInstance() // .set(QSetting.VerticesAndTrianglesShowTriangles, true); // } // // if (drawCheckBoxRight("Show triangles count (very slow)", // QSetting.VerticesAndTrianglesShowTriangles)) // { // if (QSettings.getInstance() // .get(QSetting.VerticesAndTrianglesShowVertices) == false && // QSettings.getInstance() // .get(QSetting.VerticesAndTrianglesShowTriangles) == false) // QSettings.getInstance() // .set(QSetting.VerticesAndTrianglesShowVertices, true); // } // // drawCheckBoxRight("Calculate the count including children (very slow)", // QSetting.VerticesAndTrianglesCalculateTotalCount); // drawEnum("Label size", QSetting.VerticesAndTrianglesLabelSize, // typeof(QHierarchySize)); // drawColorPicker("Vertices label color", // QSetting.VerticesAndTrianglesVerticesLabelColor); // drawColorPicker("Triangles label color", // QSetting.VerticesAndTrianglesTrianglesLabelColor); // drawSpace(1); // } // } // // private void drawComponentsComponentSettings() // { // if (drawComponentCheckBox("Components", QSetting.ComponentsShow)) // { // Rect rect = getControlRect(0, 0); // if (drawRestore()) // { // QSettings.getInstance().restore(QSetting.ComponentsShowDuringPlayMode); // QSettings.getInstance().restore(QSetting.ComponentsIconSize); // } // // drawBackground(rect.x, rect.y, rect.width, 18 * 3 + 6); // drawSpace(4); // drawCheckBoxRight("Show component during play mode", // QSetting.ComponentsShowDuringPlayMode); // drawEnum("Icon size", QSetting.ComponentsIconSize, typeof(QHierarchySizeAll)); // drawTextField("Ignore packages/classes", QSetting.ComponentsIgnore); // drawSpace(2); // } // } // // // COMPONENTS ORDER // private void drawOrderSettings() // { // if (drawRestore()) // { // QSettings.getInstance().restore(QSetting.ComponentsOrder); // } // // indentLevel += 4; // // string componentOrder = QSettings.getInstance().get(QSetting.ComponentsOrder); // string[] componentIds = componentOrder.Split(';'); // // Rect rect = getControlRect(position.width, 17 * componentIds.Length + 10, 0, 0); // if (componentsOrderList == null) // componentsOrderList = new QComponentsOrderList(this); // componentsOrderList.draw(rect, componentIds); // // indentLevel -= 4; // } // // // ADDITIONAL SETTINGS // private void drawAdditionalSettings() // { // if (drawRestore()) // { // QSettings.getInstance().restore(QSetting.AdditionalShowHiddenQHierarchyObjectList); // QSettings.getInstance().restore(QSetting.AdditionalHideIconsIfNotFit); // QSettings.getInstance().restore(QSetting.AdditionalIdentation); // QSettings.getInstance().restore(QSetting.AdditionalShowModifierWarning); // QSettings.getInstance().restore(QSetting.AdditionalBackgroundColor); // QSettings.getInstance().restore(QSetting.AdditionalActiveColor); // QSettings.getInstance().restore(QSetting.AdditionalInactiveColor); // QSettings.getInstance().restore(QSetting.AdditionalSpecialColor); // } // // drawSpace(4); // drawCheckBoxRight("Show QHierarchyObjectList GameObject", // QSetting.AdditionalShowHiddenQHierarchyObjectList); // drawCheckBoxRight("Hide icons if not fit", QSetting.AdditionalHideIconsIfNotFit); // drawIntSlider("Right indent", QSetting.AdditionalIdentation, 0, 500); // drawCheckBoxRight("Show warning when using modifiers + click", // QSetting.AdditionalShowModifierWarning); // drawColorPicker("Background color", QSetting.AdditionalBackgroundColor); // drawColorPicker("Active color", QSetting.AdditionalActiveColor); // drawColorPicker("Inactive color", QSetting.AdditionalInactiveColor); // drawColorPicker("Special color", QSetting.AdditionalSpecialColor); // drawSpace(1); // } // // // PRIVATE // private void drawSection(string title) // { // Rect rect = getControlRect(0, 24, -3, 0); // rect.width *= 2; // rect.x = 0; // GUI.Box(rect, ""); // // drawLeftLine(rect.y, rect.y + 24, yellowColor); // // rect.x = lastRect.x + 8; // rect.y += 4; // EditorGUI.LabelField(rect, title); // } // // private void drawSeparator(int spaceBefore = 0, int spaceAfter = 0, int height = 1) // { // if (spaceBefore > 0) drawSpace(spaceBefore); // Rect rect = getControlRect(0, height, 0, 0); // rect.width += 8; // EditorGUI.DrawRect(rect, separatorColor); // if (spaceAfter > 0) drawSpace(spaceAfter); // } // // private bool drawComponentCheckBox(string label, QSetting setting) // { // indentLevel += 8; // // Rect rect = getControlRect(0, 28, 0, 0); // // float rectWidth = rect.width; // bool isChecked = QSettings.getInstance().get(setting); // // rect.x -= 1; // rect.y += 7; // rect.width = 14; // rect.height = 14; // // if (GUI.Button(rect, isChecked ? checkBoxChecked : checkBoxUnchecked, GUIStyle.none)) // { // QSettings.getInstance().set(setting, !isChecked); // } // // rect.x += 14 + 10; // rect.width = rectWidth - 14 - 8; // rect.y -= (EditorGUIUtility.singleLineHeight - rect.height) * 0.5f; // rect.height = EditorGUIUtility.singleLineHeight; // // EditorGUI.LabelField(rect, label); // // indentLevel -= 8; // // return isChecked; // } // // private bool drawCheckBoxRight(string label, QSetting setting) // { // Rect rect = getControlRect(0, 18, 34, 6); // bool result = false; // bool isChecked = QSettings.getInstance().get(setting); // // float tempX = rect.x; // rect.x += rect.width - 14; // rect.y += 1; // rect.width = 14; // rect.height = 14; // // if (GUI.Button(rect, isChecked ? checkBoxChecked : checkBoxUnchecked, GUIStyle.none)) // { // QSettings.getInstance().set(setting, !isChecked); // result = true; // } // // rect.width = rect.x - tempX - 4; // rect.x = tempX; // rect.y -= (EditorGUIUtility.singleLineHeight - rect.height) * 0.5f; // rect.height = EditorGUIUtility.singleLineHeight; // // EditorGUI.LabelField(rect, label); // // return result; // } // // private void drawSpace(int value) // { // getControlRect(0, value, 0, 0); // } // // private void drawBackground(float x, float y, float width, float height) // { // EditorGUI.DrawRect(new Rect(x, y, width, height), separatorColor); // } // // private void drawLeftLine(float fromY, float toY, Color color, float width = 0) // { // EditorGUI.DrawRect(new Rect(0, fromY, width == 0 ? indentLevel : width, toY - fromY), // color); // } // // private Rect getControlRect(float width, float height, float addIndent = 0, // float remWidth = 0) // { // EditorGUILayout.GetControlRect(false, height, GUIStyle.none, // GUILayout.ExpandWidth(true)); // Rect rect = new Rect(indentLevel + addIndent, lastRect.y + lastRect.height, // (width == 0 ? totalWidth - indentLevel - addIndent - remWidth : width), height); // lastRect = rect; // return rect; // } // // private bool drawRestore() // { // if (GUI.Button(new Rect(lastRect.x + lastRect.width - 16 - 5, lastRect.y - 20, 16, 16), // restoreButtonTexture, GUIStyle.none)) // { // if (EditorUtility.DisplayDialog("Restore", "Restore default settings?", "Ok", // "Cancel")) // { // return true; // } // } // // return false; // } // // // GUI COMPONENTS // private void drawLabel(string label) // { // Rect rect = getControlRect(0, 16, 34, 6); // rect.y -= (EditorGUIUtility.singleLineHeight - rect.height) * 0.5f; // EditorGUI.LabelField(rect, label); // drawSpace(2); // } // // private void drawTextField(string label, QSetting setting) // { // string currentValue = QSettings.getInstance().get(setting); // string newValue = // EditorGUI.TextField(getControlRect(0, 16, 34, 6), label, currentValue); // if (!currentValue.Equals(newValue)) QSettings.getInstance().set(setting, newValue); // drawSpace(2); // } // // private bool drawFoldout(string label, QSetting setting) // { // #if UNITY_2019_1_OR_NEWER // Rect foldoutRect = getControlRect(0, 16, 19, 6); // #else // Rect foldoutRect = getControlRect(0, 16, 22, 6); // #endif // bool foldoutValue = QSettings.getInstance().get(setting); // bool newFoldoutValue = EditorGUI.Foldout(foldoutRect, foldoutValue, label); // if (foldoutValue != newFoldoutValue) // QSettings.getInstance().set(setting, newFoldoutValue); // drawSpace(2); // return newFoldoutValue; // } // // private void drawColorPicker(string label, QSetting setting) // { // Color currentColor = QSettings.getInstance().getColor(setting); // Color newColor = // EditorGUI.ColorField(getControlRect(0, 16, 34, 6), label, currentColor); // if (!currentColor.Equals(newColor)) QSettings.getInstance().setColor(setting, newColor); // drawSpace(2); // } // // private Enum drawEnum(string label, QSetting setting, Type enumType) // { // Enum currentEnum = // (Enum)Enum.ToObject(enumType, QSettings.getInstance().get(setting)); // Enum newEnumValue; // if (!(newEnumValue = // EditorGUI.EnumPopup(getControlRect(0, 16, 34, 6), label, currentEnum)) // .Equals(currentEnum)) // QSettings.getInstance().set(setting, (int)(object)newEnumValue); // drawSpace(2); // return newEnumValue; // } // // private void drawIntSlider(string label, QSetting setting, int minValue, int maxValue) // { // Rect rect = getControlRect(0, 16, 34, 4); // int currentValue = QSettings.getInstance().get(setting); // int newValue = EditorGUI.IntSlider(rect, label, currentValue, minValue, maxValue); // if (currentValue != newValue) QSettings.getInstance().set(setting, newValue); // drawSpace(2); // } // // private void drawFloatSlider(string label, QSetting setting, float minValue, float maxValue) // { // Rect rect = getControlRect(0, 16, 34, 4); // float currentValue = QSettings.getInstance().get(setting); // float newValue = EditorGUI.Slider(rect, label, currentValue, minValue, maxValue); // if (currentValue != newValue) QSettings.getInstance().set(setting, newValue); // drawSpace(2); // } } } ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/VHierarchy/HierarchySettingsWindow.cs.meta ================================================ fileFormatVersion: 2 guid: 311dd60af7f888a4ea46d48565c35ed1 timeCreated: 1474888502 licenseType: Store MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/VHierarchy/VHierarchy.cs ================================================ using UnityEngine; using UnityEditor; using System; using System.Collections.Generic; using VirtueSky.Hierarchy.HComponent; using VirtueSky.Hierarchy.HComponent.Base; using VirtueSky.Hierarchy.Data; using VirtueSky.Hierarchy.Helper; using System.Reflection; namespace VirtueSky.Hierarchy.phierarchy { public class VHierarchy { // PRIVATE private HashSet errorHandled = new HashSet(); private Dictionary componentDictionary; private List preComponents; private List orderedComponents; private bool hideIconsIfThereIsNoFreeSpace; private int indentation; private Texture2D trimIcon; private Color backgroundColor; private Color inactiveColor; // CONSTRUCTOR public VHierarchy () { componentDictionary = new Dictionary(); componentDictionary.Add((int)HierarchyComponentEnum.LockComponent , new LockComponent()); componentDictionary.Add((int)HierarchyComponentEnum.VisibilityComponent , new VisibilityComponent()); componentDictionary.Add((int)HierarchyComponentEnum.StaticComponent , new StaticComponent()); componentDictionary.Add((int)HierarchyComponentEnum.RendererComponent , new RendererComponent()); componentDictionary.Add((int)HierarchyComponentEnum.TagAndLayerComponent , new TagLayerComponent()); componentDictionary.Add((int)HierarchyComponentEnum.GameObjectIconComponent , new GameObjectIconComponent()); componentDictionary.Add((int)HierarchyComponentEnum.ErrorComponent , new ErrorComponent()); componentDictionary.Add((int)HierarchyComponentEnum.TagIconComponent , new TagIconComponent()); componentDictionary.Add((int)HierarchyComponentEnum.LayerIconComponent , new LayerIconComponent()); componentDictionary.Add((int)HierarchyComponentEnum.ColorComponent , new ColorComponent()); componentDictionary.Add((int)HierarchyComponentEnum.ComponentsComponent , new ComponentsComponent()); componentDictionary.Add((int)HierarchyComponentEnum.ChildrenCountComponent , new ChildrenCountComponent()); componentDictionary.Add((int)HierarchyComponentEnum.PrefabComponent , new PrefabComponent()); componentDictionary.Add((int)HierarchyComponentEnum.VerticesAndTrianglesCount , new VerticesAndTrianglesCountComponent()); preComponents = new List(); preComponents.Add(new MonoBehaviorIconComponent()); preComponents.Add(new TreeMapComponent()); preComponents.Add(new SeparatorComponent()); orderedComponents = new List(); trimIcon = HierarchyResources.getInstance().getTexture(HierarchyTexture.HierarchyTrimIcon); HierarchySettings.getInstance().addEventListener(HierarchySetting.AdditionalIdentation , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.ComponentsOrder , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.AdditionalHideIconsIfNotFit , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.AdditionalBackgroundColor , settingsChanged); HierarchySettings.getInstance().addEventListener(HierarchySetting.AdditionalInactiveColor , settingsChanged); settingsChanged(); } // PRIVATE private void settingsChanged() { string componentOrder = HierarchySettings.getInstance().get(HierarchySetting.ComponentsOrder); string[] componentIds = componentOrder.Split(';'); if (componentIds.Length != HierarchySettings.DEFAULT_ORDER_COUNT) { HierarchySettings.getInstance().set(HierarchySetting.ComponentsOrder, HierarchySettings.DEFAULT_ORDER, false); componentIds = HierarchySettings.DEFAULT_ORDER.Split(';'); } orderedComponents.Clear(); for (int i = 0; i < componentIds.Length; i++) orderedComponents.Add(componentDictionary[int.Parse(componentIds[i])]); orderedComponents.Add(componentDictionary[(int)HierarchyComponentEnum.ComponentsComponent]); indentation = HierarchySettings.getInstance().get(HierarchySetting.AdditionalIdentation); hideIconsIfThereIsNoFreeSpace = HierarchySettings.getInstance().get(HierarchySetting.AdditionalHideIconsIfNotFit); backgroundColor = HierarchySettings.getInstance().getColor(HierarchySetting.AdditionalBackgroundColor); inactiveColor = HierarchySettings.getInstance().getColor(HierarchySetting.AdditionalInactiveColor); } public void hierarchyWindowItemOnGUIHandler(int instanceId, Rect selectionRect) { try { HierarchyColorUtils.setDefaultColor(GUI.color); GameObject gameObject = (GameObject)EditorUtility.InstanceIDToObject(instanceId); if (gameObject == null) return; Rect curRect = new Rect(selectionRect); curRect.width = 16; curRect.x += selectionRect.width - indentation; float gameObjectNameWidth = hideIconsIfThereIsNoFreeSpace ? GUI.skin.label.CalcSize(new GUIContent(gameObject.name)).x : 0; ObjectList objectList = HierarchyObjectListManager.getInstance().getObjectList(gameObject, false); drawComponents(orderedComponents, selectionRect, ref curRect, gameObject, objectList, true, hideIconsIfThereIsNoFreeSpace ? selectionRect.x + gameObjectNameWidth + 7 : 0); errorHandled.Remove(instanceId); } catch (Exception exception) { if (errorHandled.Add(instanceId)) { Debug.LogError(exception.ToString()); } } } private void drawComponents(List components, Rect selectionRect, ref Rect rect, GameObject gameObject, ObjectList objectList, bool drawBackground = false, float minX = 50) { if (Event.current.type == EventType.Repaint) { int toComponent = components.Count; LayoutStatus layoutStatus = LayoutStatus.Success; for (int i = 0, n = toComponent; i < n; i++) { BaseComponent component = components[i]; if (component.isEnabled()) { layoutStatus = component.layout(gameObject, objectList, selectionRect, ref rect, rect.x - minX); if (layoutStatus != LayoutStatus.Success) { toComponent = layoutStatus == LayoutStatus.Failed ? i : i + 1; rect.x -= 7; break; } } else { component.disabledHandler(gameObject, objectList); } } if (drawBackground) { if (backgroundColor.a != 0) { rect.width = selectionRect.x + selectionRect.width - rect.x /*- indentation*/; EditorGUI.DrawRect(rect, backgroundColor); } drawComponents(preComponents , selectionRect, ref rect, gameObject, objectList); } for (int i = 0, n = toComponent; i < n; i++) { BaseComponent component = components[i]; if (component.isEnabled()) { component.draw(gameObject, objectList, selectionRect); } } if (layoutStatus != LayoutStatus.Success) { rect.width = 7; HierarchyColorUtils.setColor(inactiveColor); GUI.DrawTexture(rect, trimIcon); HierarchyColorUtils.clearColor(); } } else if (Event.current.isMouse) { for (int i = 0, n = components.Count; i < n; i++) { BaseComponent component = components[i]; if (component.isEnabled()) { if (component.layout(gameObject, objectList, selectionRect, ref rect, rect.x - minX) != LayoutStatus.Failed) { component.eventHandler(gameObject, objectList, Event.current); } } } } } } } ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/VHierarchy/VHierarchy.cs.meta ================================================ fileFormatVersion: 2 guid: 4b7e0353599820d438074ea45a106853 timeCreated: 1474888198 licenseType: Store MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts/VHierarchy.meta ================================================ fileFormatVersion: 2 guid: cc4f43cb5bd4bf546a9edf40a361f0f5 folderAsset: yes timeCreated: 1515657177 licenseType: Store DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Hierarchy/Editor/Scripts.meta ================================================ fileFormatVersion: 2 guid: a37008235cb5c0c4b9ca8932a016d63c folderAsset: yes timeCreated: 1515657177 licenseType: Store DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Hierarchy/Editor.meta ================================================ fileFormatVersion: 2 guid: 325ffd836cb52054d9f615250b95398d folderAsset: yes timeCreated: 1515657177 licenseType: Store DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Hierarchy/FolderHierarchy/HeaderHierarchy.cs ================================================ using UnityEngine; using VirtueSky.Inspector; using VirtueSky.Utils; namespace VirtueSky.Hierarchy { [ExecuteInEditMode] [EditorIcon("icon_hierarchy"), HideMonoScript] public class HeaderHierarchy : MonoBehaviour { #region Variables public enum TextAlignment { Left, Center } [TitleColor("Text", CustomColor.Gold, CustomColor.Aqua)] [SerializeField] public bool customText; [ShowIf(nameof(customText)), SerializeField] public Color32 textColor = InspectorUtility.textNormalColor; [Space] [SerializeField] public FontStyle textStyle = FontStyle.BoldAndItalic; [SerializeField] public TextAlignment textAlignment = TextAlignment.Left; [TitleColor("Highlight", CustomColor.Coral, CustomColor.Lime)] [Space, SerializeField] public bool customHighlight; [ShowIf(nameof(customHighlight)), SerializeField] public Color32 highlightColor = InspectorUtility.cyanColor; #endregion } // class end } ================================================ FILE: VirtueSky/Hierarchy/FolderHierarchy/HeaderHierarchy.cs.meta ================================================ fileFormatVersion: 2 guid: e3036e8f2fe4f8e4bb99b79fe6ebdf01 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 422b56a3ea31444cd82f5ee33cbd31d4, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Hierarchy/FolderHierarchy/HeaderHierarchyIcon.cs ================================================ #if UNITY_EDITOR using System.Linq; using UnityEditor; using UnityEngine; using VirtueSky.UtilsEditor; namespace VirtueSky.Hierarchy { [InitializeOnLoad] public class HeaderHierarchyIcon { #region Static Variables // icons private static string assetPath = "/VirtueSky/Hierarchy/Icons"; private static Texture2D icon_HierarchyHighlight; #endregion //---------------------------------------------------------------------------------------------------- #region Contructors static HeaderHierarchyIcon() { // subscribe to inspector updates EditorApplication.hierarchyWindowItemOnGUI += EditorApplication_hierarchyWindowItemOnGUI; } #endregion //---------------------------------------------------------------------------------------------------- #region Private Functions private static void CreateHierarchyIcon_Highlight() { icon_HierarchyHighlight = FileExtension.FindAssetWithPath("HierarchyHighlight.png", assetPath); } private static void EditorApplication_hierarchyWindowItemOnGUI(int instanceID, Rect position) { // check for valid draw if (Event.current.type != EventType.Repaint) { return; } GameObject gameObject = EditorUtility.InstanceIDToObject(instanceID) as GameObject; if (gameObject != null) { HeaderHierarchy component = gameObject.GetComponent(); if (component != null) { // cache values int hierarchyPixelHeight = 16; bool isSelected = Selection.instanceIDs.Contains(instanceID); bool isActive = component.isActiveAndEnabled; Color32 defaultContentColor = GUI.contentColor; Color32 textColor; Color32 backgroundColor; if (isActive || isSelected) { // text if (component.customText) { textColor = component.textColor; } else { textColor = InspectorUtility.textNormalColor; } } else { // text if (component.customText) { textColor = (Color)component.textColor * 0.6f; } else { textColor = InspectorUtility.textDisabledColor; } } // draw background if (isSelected) { backgroundColor = InspectorUtility.backgroundActiveColor; } else { backgroundColor = InspectorUtility.backgroundNormalColorLight; } Rect backgroundPosition = new Rect(position.xMin, position.yMin, position.width + hierarchyPixelHeight, position.height); EditorGUI.DrawRect(backgroundPosition, backgroundColor); // check icon exists if (!icon_HierarchyHighlight) { CreateHierarchyIcon_Highlight(); } // draw highlight if (component.customHighlight) { GUI.contentColor = component.highlightColor; Rect iconPosition = new Rect(position.xMin, position.yMin, icon_HierarchyHighlight.width, icon_HierarchyHighlight.height); GUIContent iconGUIContent = new GUIContent(icon_HierarchyHighlight); EditorGUI.LabelField(iconPosition, iconGUIContent); GUI.contentColor = defaultContentColor; } // draw text GUIStyle hierarchyText = new GUIStyle() { }; hierarchyText.normal = new GUIStyleState() { textColor = textColor }; hierarchyText.fontStyle = component.textStyle; int offsetX; if (component.textAlignment == HeaderHierarchy.TextAlignment.Center) { hierarchyText.alignment = TextAnchor.MiddleCenter; offsetX = 0; } else { hierarchyText.alignment = TextAnchor.MiddleLeft; offsetX = hierarchyPixelHeight + 2; } Rect textOffset = new Rect(position.xMin + offsetX, position.yMin, position.width, position.height); EditorGUI.LabelField(textOffset, component.name, hierarchyText); } } } #endregion } // class end } #endif ================================================ FILE: VirtueSky/Hierarchy/FolderHierarchy/HeaderHierarchyIcon.cs.meta ================================================ fileFormatVersion: 2 guid: 051786f9cab235441ac9f2abcea3bd94 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Hierarchy/FolderHierarchy/HierarchyHeader.asmdef ================================================ { "name": "HierarchyHeader", "rootNamespace": "", "references": [ "GUID:324caed91501a9c47a04ebfd87b68794", "GUID:c904f6d969e991d459a0843b71c22ec5", "GUID:c282fd4f3fc2c7540914e85842a013c7" ], "includePlatforms": [], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], "versionDefines": [], "noEngineReferences": false } ================================================ FILE: VirtueSky/Hierarchy/FolderHierarchy/HierarchyHeader.asmdef.meta ================================================ fileFormatVersion: 2 guid: d4acae227198a6b4395e2c4a4b0b6a56 AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Hierarchy/FolderHierarchy/InspectorUtility.cs ================================================ using UnityEngine; #if UNITY_EDITOR using UnityEditor; #endif namespace VirtueSky.Hierarchy { public static class InspectorUtility { #region Static Variables // blank public static readonly Color32 blankColor = new Color32(000, 000, 000, 000); public static readonly Color32 cyanColor = new Color32(000, 179, 223, 255); public static readonly Color32 yellowColor = new Color32(223, 179, 000, 255); // background public static readonly Color32 backgroundNormalColorLight = new Color32(056, 056, 056, 255); public static readonly Color32 backgroundNormalColor = new Color32(051, 051, 051, 255); public static readonly Color32 backgroundNormalColorDark = new Color32(045, 045, 045, 255); public static readonly Color32 backgroundActiveColor = new Color32(044, 093, 135, 255); public static readonly Color32 backgroundHoverColor = new Color32(056, 056, 056, 255); public static readonly Color32 backgroundShadowColor = new Color32(042, 042, 042, 255); public static readonly Color32 backgroundSeperatorColor = new Color32(035, 035, 035, 255); // selected public static readonly Color32 buttonSelectedColor = new Color32(128, 179, 223, 255); // button - normal, hover, active public static readonly Color32 buttonHoverColor = new Color32(099, 099, 099, 255); public static readonly Color32 buttonHoverBorderColor = new Color32(028, 028, 028, 255); public static readonly Color32 buttonActiveColor = new Color32(000, 128, 223, 255); public static readonly Color32 buttonActiveBorderColor = new Color32(010, 010, 010, 255); // text public static readonly Color32 textNormalColor = new Color32(179, 179, 179, 255); public static readonly Color32 textDisabledColor = new Color32(113, 113, 113, 255); #endregion //---------------------------------------------------------------------------------------------------- #region Helper Functions #if UNITY_EDITOR public static void DrawInspectorLine(Color32 lineColor) { GUIStyle horizontalLine = new GUIStyle { normal = { background = EditorGUIUtility.whiteTexture }, margin = new RectOffset(0, 0, 4, 4), fixedHeight = 1 }; Color defaultGUIColor = GUI.color; GUI.color = lineColor; EditorGUILayout.Space(); GUILayout.Box(GUIContent.none, horizontalLine); GUI.color = defaultGUIColor; } #endif public static Texture2D CreateTexture(int width, int height, int border, bool isRounded, Color32 backgroundColor, Color32 borderColor) { Color[] pixels = new Color[width * height]; int pixelIndex = 0; if (isRounded) { for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { // if at corner add corner color if ((i < border || i >= width - border) && (j < border || j >= width - border)) { pixels[pixelIndex] = blankColor; } // otherwise if on border... else if ((i < border || i >= width - border || j < border || j >= width - border) || ((i < border * 2 || i >= width - border * 2) && (j < border * 2 || j >= width - border * 2))) { // ... add border color pixels[pixelIndex] = borderColor; } else { // ... otherwise add background color pixels[pixelIndex] = backgroundColor; } pixelIndex++; } } } else { for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { // if on border... if (i < border || i >= width - border || j < border || j >= width - border) { // ... add border color pixels[pixelIndex] = borderColor; } else { // ... otherwise add background color pixels[pixelIndex] = backgroundColor; } pixelIndex++; } } } Texture2D result = new Texture2D(width, height); result.SetPixels(pixels); result.Apply(); return result; } public static Texture2D TintTexture(Texture2D texture2D, Color tint) { // null check if (!texture2D) { return null; } int width = texture2D.width; int height = texture2D.height; Color[] pixels = new Color[width * height]; int pixelIndex = 0; for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { pixels[pixelIndex] = texture2D.GetPixel(j, i) * tint; pixelIndex++; } } Texture2D result = new Texture2D(width, height); result.SetPixels(pixels); result.Apply(); return result; } public static Texture2D AddBorderToTexture(Texture2D texture2D, Color borderColor, int borderThickness) { // null check if (!texture2D) { return null; } int width = texture2D.width; int height = texture2D.height; Color[] pixels = new Color[width * height]; int pixelIndex = 0; for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { // if on border... if (i < borderThickness || i >= width - borderThickness || j < borderThickness || j >= width - borderThickness) { // ... add border color pixels[pixelIndex] = borderColor; } else { // ... otherwise get pixel color pixels[pixelIndex] = pixels[pixelIndex] = texture2D.GetPixel(j, i); } pixelIndex++; } } Texture2D result = new Texture2D(width, height); result.SetPixels(pixels); result.Apply(); return result; } #endregion //---------------------------------------------------------------------------------------------------- #region Custom Button Styles public static GUIStyle Style_DefaultButton() { return new GUIStyle(GUI.skin.button); } public static GUIStyle Style_Button() { GUIStyle buttonStyle = new GUIStyle(); buttonStyle.fontSize = 9; buttonStyle.alignment = TextAnchor.MiddleCenter; buttonStyle.normal.textColor = textNormalColor; buttonStyle.hover.textColor = textNormalColor; buttonStyle.active.textColor = textNormalColor; buttonStyle.normal.background = CreateTexture(20, 20, 1, true, blankColor, blankColor); buttonStyle.hover.background = CreateTexture(20, 20, 1, true, buttonHoverColor, buttonHoverBorderColor); buttonStyle.active.background = CreateTexture(20, 20, 1, true, buttonActiveColor, buttonActiveBorderColor); return buttonStyle; } public static GUIStyle Style_ImageButton(Texture2D normalTexture, int outline = 0) { Color32 hover = new Color32(223, 223, 223, 255); Color32 active = new Color32(079, 128, 179, 255); if (0 < outline) { return Style_ImageButton(normalTexture, active, outline); } else { return Style_ImageButton(normalTexture, hover, active); } } public static GUIStyle Style_ImageButton(Texture2D normalTexture, Color activeTint, int thickness) { GUIStyle buttonStyle = new GUIStyle(); Texture2D hoverTexture = AddBorderToTexture(normalTexture, activeTint, thickness); Texture2D activeTexture = TintTexture(normalTexture, activeTint); buttonStyle.normal.background = normalTexture; buttonStyle.hover.background = hoverTexture; buttonStyle.active.background = activeTexture; return buttonStyle; } public static GUIStyle Style_ImageButton(Texture2D normalTexture, Color hoverTint, Color activeTint) { GUIStyle buttonStyle = new GUIStyle(); Texture2D hoverTexture = TintTexture(normalTexture, hoverTint); Texture2D activeTexture = TintTexture(normalTexture, activeTint); buttonStyle.normal.background = normalTexture; buttonStyle.hover.background = hoverTexture; buttonStyle.active.background = activeTexture; return buttonStyle; } public static GUIStyle Style_StealthButton() { GUIStyle buttonStyle = new GUIStyle(); buttonStyle.fontSize = 10; buttonStyle.normal.textColor = Color.grey; return buttonStyle; } #endregion } // class end } ================================================ FILE: VirtueSky/Hierarchy/FolderHierarchy/InspectorUtility.cs.meta ================================================ fileFormatVersion: 2 guid: 1abe08dca56cc5a42920f170820c5760 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Hierarchy/FolderHierarchy.meta ================================================ fileFormatVersion: 2 guid: 643b5b480bb19af43a78bf179abb87fc folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Hierarchy/Icons/HierarchyHighlight.png.meta ================================================ fileFormatVersion: 2 guid: 01b0134cecf44934f86df7ffd52f333d TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 51 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 51 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Hierarchy/Icons.meta ================================================ fileFormatVersion: 2 guid: b64e9c6185a69634386d98c3cf6888cf folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Hierarchy/Scripts/HierarchyRuntime.asmdef ================================================ { "name": "HierarchyRuntime", "rootNamespace": "", "references": [], "includePlatforms": [], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], "versionDefines": [], "noEngineReferences": false } ================================================ FILE: VirtueSky/Hierarchy/Scripts/HierarchyRuntime.asmdef.meta ================================================ fileFormatVersion: 2 guid: 211f9e8f16a5ff644946a29c81bedf42 AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Hierarchy/Scripts/ObjectList.cs ================================================ using UnityEngine; using System; using System.Collections; using System.Collections.Generic; #if UNITY_EDITOR using UnityEditor; #endif namespace VirtueSky.Hierarchy { [ExecuteInEditMode] [AddComponentMenu("")] public class ObjectList : MonoBehaviour, ISerializationCallbackReceiver { public static List instances = new List(); public List lockedObjects = new List(); public List editModeVisibileObjects = new List(); public List editModeInvisibleObjects = new List(); public List wireframeHiddenObjects = new List(); public Dictionary gameObjectColor = new Dictionary(); public List gameObjectColorKeys = new List(); public List gameObjectColorValues = new List(); public void Awake() { checkIntegrity(); foreach (GameObject editModeGameObject in editModeVisibileObjects) editModeGameObject.SetActive(!Application.isPlaying); foreach (GameObject editModeGameObject in editModeInvisibleObjects) editModeGameObject.SetActive(Application.isPlaying); if (!Application.isEditor && Application.isPlaying) { instances.Remove(this); DestroyImmediate(gameObject); return; } instances.RemoveAll(item => item == null); if (!instances.Contains(this)) instances.Add(this); } public void OnEnable() { if (!instances.Contains(this)) instances.Add(this); #if UNITY_EDITOR foreach (GameObject wireframeGameObject in wireframeHiddenObjects) { Renderer renderer = wireframeGameObject.GetComponent(); if (renderer != null) { #if UNITY_5_5_OR_NEWER EditorUtility.SetSelectedRenderState(renderer, EditorSelectedRenderState.Hidden); #else EditorUtility.SetSelectedWireframeHidden(renderer, true); #endif } } #endif } public void OnDestroy() { if (!Application.isPlaying) { checkIntegrity(); foreach (GameObject gameObject in editModeVisibileObjects) gameObject.SetActive(false); foreach (GameObject gameObject in editModeInvisibleObjects) gameObject.SetActive(true); foreach (GameObject gameObject in lockedObjects) gameObject.hideFlags &= ~HideFlags.NotEditable; instances.Remove(this); } } public void merge(ObjectList anotherInstance) { for (int i = anotherInstance.lockedObjects.Count - 1; i >= 0; i--) { if (!lockedObjects.Contains(anotherInstance.lockedObjects[i])) lockedObjects.Add(anotherInstance.lockedObjects[i]); } for (int i = anotherInstance.editModeVisibileObjects.Count - 1; i >= 0; i--) { if (!editModeVisibileObjects.Contains(anotherInstance.editModeVisibileObjects[i])) editModeVisibileObjects.Add(anotherInstance.editModeVisibileObjects[i]); } for (int i = anotherInstance.editModeInvisibleObjects.Count - 1; i >= 0; i--) { if (!editModeInvisibleObjects.Contains(anotherInstance.editModeInvisibleObjects[i])) editModeInvisibleObjects.Add(anotherInstance.editModeInvisibleObjects[i]); } for (int i = anotherInstance.wireframeHiddenObjects.Count - 1; i >= 0; i--) { if (!wireframeHiddenObjects.Contains(anotherInstance.wireframeHiddenObjects[i])) wireframeHiddenObjects.Add(anotherInstance.wireframeHiddenObjects[i]); } for (int i = anotherInstance.gameObjectColorKeys.Count - 1; i >= 0; i--) { if (!gameObjectColorKeys.Contains(anotherInstance.gameObjectColorKeys[i])) { gameObjectColorKeys.Add(anotherInstance.gameObjectColorKeys[i]); gameObjectColorValues.Add(anotherInstance.gameObjectColorValues[i]); gameObjectColor.Add(anotherInstance.gameObjectColorKeys[i], anotherInstance.gameObjectColorValues[i]); } } } public void checkIntegrity() { lockedObjects.RemoveAll(item => item == null); editModeVisibileObjects.RemoveAll(item => item == null); editModeInvisibleObjects.RemoveAll(item => item == null); wireframeHiddenObjects.RemoveAll(item => item == null); for (int i = gameObjectColorKeys.Count - 1; i >= 0; i--) { if (gameObjectColorKeys[i] == null) { gameObjectColorKeys.RemoveAt(i); gameObjectColorValues.RemoveAt(i); } } OnAfterDeserialize(); } public void OnBeforeSerialize() { gameObjectColorKeys.Clear(); gameObjectColorValues.Clear(); foreach (KeyValuePair pair in gameObjectColor) { gameObjectColorKeys.Add(pair.Key); gameObjectColorValues.Add(pair.Value); } } public void OnAfterDeserialize() { gameObjectColor.Clear(); for (int i = 0; i < gameObjectColorKeys.Count; i++) gameObjectColor.Add(gameObjectColorKeys[i], gameObjectColorValues[i]); } } } ================================================ FILE: VirtueSky/Hierarchy/Scripts/ObjectList.cs.meta ================================================ fileFormatVersion: 2 guid: 845e8bd83609e3549af5a311ad811681 timeCreated: 1475506195 licenseType: Store MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: -10000 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Hierarchy/Scripts.meta ================================================ fileFormatVersion: 2 guid: 7de9a0dec5e15f64fa8b3c79974355f0 folderAsset: yes timeCreated: 1515657177 licenseType: Store DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Hierarchy.meta ================================================ fileFormatVersion: 2 guid: b66613caeea30044ab544ffda293c903 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Iap/Editor/IapSettingEditor.cs ================================================ #if VIRTUESKY_IAP using System.IO; using System.Linq; using UnityEditor; using UnityEngine; using VirtueSky.UtilsEditor; namespace VirtueSky.Iap { [CustomEditor(typeof(IapSetting), true)] public class IapSettingEditor : Editor { private IapSetting _iapSetting; private SerializedProperty _skusData; private SerializedProperty _products; private SerializedProperty _isValidatePurchase; private SerializedProperty _isCustomValidatePurchase; private SerializedProperty _googlePlayStoreKey; void Initialize() { _iapSetting = target as IapSetting; _skusData = serializedObject.FindProperty("skusData"); _products = serializedObject.FindProperty("products"); _isValidatePurchase = serializedObject.FindProperty("isValidatePurchase"); _isCustomValidatePurchase = serializedObject.FindProperty("isCustomValidatePurchase"); _googlePlayStoreKey = serializedObject.FindProperty("googlePlayStoreKey"); } public override void OnInspectorGUI() { serializedObject.Update(); Initialize(); EditorGUILayout.PropertyField(_skusData); EditorGUILayout.PropertyField(_products); if (GUILayout.Button("Generate Product From SkusData")) { GenerateProduct(); } EditorGUILayout.PropertyField(_isValidatePurchase); if (_isValidatePurchase.boolValue) { EditorGUILayout.PropertyField(_isCustomValidatePurchase); EditorGUILayout.PropertyField(_googlePlayStoreKey); if (GUILayout.Button("Obfuscator Key")) { ObfuscatorKey(); } } serializedObject.ApplyModifiedProperties(); } void GenerateProduct() { _iapSetting.Products.Clear(); for (int i = 0; i < _iapSetting.SkusData.Count; i++) { bool isCustomName = false; var data = _iapSetting.SkusData[i]; string itemName = data.Id.Split('.').Last(); if (!string.IsNullOrEmpty(data.customProductName)) { isCustomName = true; itemName = data.customProductName; } var itemDataVariable = CreateAsset.CreateAndGetScriptableAssetByName("/Iap/Products", isCustomName ? $"{itemName.ToLower()}" : $"iap_{itemName.ToLower()}"); itemDataVariable.androidId = data.androidId; itemDataVariable.iosId = data.iosId; itemDataVariable.productType = data.productType; _iapSetting.Products.Add(itemDataVariable); } serializedObject.ApplyModifiedProperties(); EditorUtility.SetDirty(target); AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); } void ObfuscatorKey() { var googleError = ""; var appleError = ""; ObfuscationGenerator.ObfuscateSecrets(includeGoogle: true, appleError: ref googleError, googleError: ref appleError, googlePlayPublicKey: _iapSetting.GooglePlayStoreKey); string pathAsmdef = FileExtension.GetPathFileInCurrentEnvironment( $"VirtueSky/Utils/Editor/TemplateAssembly/PurchasingGeneratedAsmdef.txt"); string pathAsmdefMeta = FileExtension.GetPathFileInCurrentEnvironment( $"VirtueSky/Utils/Editor/TemplateAssembly/PurchasingGeneratedAsmdefMeta.txt"); var asmdef = (TextAsset)AssetDatabase.LoadAssetAtPath(pathAsmdef, typeof(TextAsset)); var meta = (TextAsset)AssetDatabase.LoadAssetAtPath(pathAsmdefMeta, typeof(TextAsset)); string path = Path.Combine(TangleFileConsts.k_OutputPath, "virtuesky.purchasing.generate.asmdef"); string pathMeta = Path.Combine(TangleFileConsts.k_OutputPath, "virtuesky.purchasing.generate.asmdef.meta"); if (!File.Exists(path)) { var writer = new StreamWriter(path, false); writer.Write(asmdef.text); writer.Close(); } if (!File.Exists(pathMeta)) { var writer = new StreamWriter(pathMeta, false); writer.Write(meta.text); writer.Close(); } AssetDatabase.ImportAsset(path); } } } #endif ================================================ FILE: VirtueSky/Iap/Editor/IapSettingEditor.cs.meta ================================================ fileFormatVersion: 2 guid: b423ca1e7e1e4e6ca2c02e2f47fe5551 timeCreated: 1700036744 ================================================ FILE: VirtueSky/Iap/Editor/ObfuscationGenerator.cs ================================================ #if UNITY_EDITOR using System; using System.Collections.Generic; using System.IO; using UnityEditor; using UnityEngine; namespace VirtueSky.Iap { public class ObfuscationGenerator { private const string m_GeneratedCredentialsTemplateFilename = "IAPGeneratedCredentials.cs.template"; private const string m_GeneratedCredentialsTemplateFilenameNoExtension = "IAPGeneratedCredentials.cs"; private const string k_AppleCertPath = "Packages/com.unity.purchasing/Editor/AppleIncRootCertificate.cer"; private const string k_AppleStoreKitTestCertPath = "Packages/com.unity.purchasing/Editor/StoreKitTestCertificate.cer"; private const string k_AppleClassIncompleteErr = "Invalid Apple Root Certificate"; private const string k_AppleStoreKitTestClassIncompleteErr = "Invalid Apple StoreKit Test Certificate"; internal static string ObfuscateAppleSecrets() { var appleError = WriteObfuscatedAppleClassAsAsset(); AssetDatabase.Refresh(); return appleError; } internal static string ObfuscateGoogleSecrets(string googlePlayPublicKey) { var googleError = WriteObfuscatedGooglePlayClassAsAsset(googlePlayPublicKey); AssetDatabase.Refresh(); return googleError; } /// /// Generates specified obfuscated class files. /// internal static void ObfuscateSecrets(bool includeGoogle, ref string appleError, ref string googleError, string googlePlayPublicKey) { try { // First things first! Obfuscate! XHTLOA! appleError = WriteObfuscatedAppleClassAsAsset(); if (includeGoogle) { googleError = WriteObfuscatedGooglePlayClassAsAsset(googlePlayPublicKey); } } catch (Exception e) { Debug.LogWarning(e.StackTrace); } // Ensure all the Tangle classes exist, even if they were not generated at this time. if (!DoesGooglePlayTangleClassExist()) { try { WriteObfuscatedClassAsAsset(TangleFileConsts.k_GooglePlayClassPrefix, 0, new int[0], new byte[0], false); } catch (Exception e) { Debug.LogWarning(e.StackTrace); } } AssetDatabase.Refresh(); } private static string WriteObfuscatedAppleClassAsAsset() { var err = WriteObfuscatedAppleClassAsAsset(k_AppleCertPath, k_AppleClassIncompleteErr, TangleFileConsts.k_AppleClassPrefix); if (err == null) { err = WriteObfuscatedAppleClassAsAsset(k_AppleStoreKitTestCertPath, k_AppleStoreKitTestClassIncompleteErr, TangleFileConsts.k_AppleStoreKitTestClassPrefix); } return err; } private static string WriteObfuscatedAppleClassAsAsset(string certPath, string classIncompleteErr, string classPrefix) { string appleError = null; var key = 0; var order = new int[0]; var tangled = new byte[0]; try { var bytes = File.ReadAllBytes(certPath); order = new int[bytes.Length / 20 + 1]; // TODO: Integrate with upgraded Tangle! tangled = TangleObfuscator.Obfuscate(bytes, order, out key); } catch (Exception e) { Debug.LogWarning($"{classIncompleteErr}. Generating incomplete credentials file. " + e); appleError = $" {classIncompleteErr}"; } WriteObfuscatedClassAsAsset(classPrefix, key, order, tangled, tangled.Length != 0); return appleError; } private static string WriteObfuscatedGooglePlayClassAsAsset(string googlePlayPublicKey) { string googleError = null; var key = 0; var order = new int[0]; var tangled = new byte[0]; try { var bytes = Convert.FromBase64String(googlePlayPublicKey); order = new int[bytes.Length / 20 + 1]; tangled = TangleObfuscator.Obfuscate(bytes, order, out key); } catch (Exception e) { Debug.LogWarning("Invalid Google Play Public Key. Generating incomplete credentials file. " + e); googleError = " The Google Play License Key is invalid. GooglePlayTangle was generated with incomplete credentials."; } WriteObfuscatedClassAsAsset(TangleFileConsts.k_GooglePlayClassPrefix, key, order, tangled, tangled.Length != 0); return googleError; } private static string FullPathForTangleClass(string classnamePrefix) { return Path.Combine(TangleFileConsts.k_OutputPath, string.Format($"{classnamePrefix}{TangleFileConsts.k_ObfuscationClassSuffix}")); } internal static bool DoesAppleTangleClassExist() { return ObfuscatedClassExists(TangleFileConsts.k_AppleClassPrefix) && ObfuscatedClassExists(TangleFileConsts.k_AppleStoreKitTestClassPrefix); } internal static bool DoesGooglePlayTangleClassExist() { return ObfuscatedClassExists(TangleFileConsts.k_GooglePlayClassPrefix); } private static bool ObfuscatedClassExists(string classnamePrefix) { return File.Exists(FullPathForTangleClass(classnamePrefix)); } private static void WriteObfuscatedClassAsAsset(string classnamePrefix, int key, int[] order, byte[] data, bool populated) { var substitutionDictionary = new Dictionary() { { "{NAME}", classnamePrefix.ToString() }, { "{KEY}", key.ToString() }, { "{ORDER}", String.Format("{0}", String.Join(",", Array.ConvertAll(order, i => i.ToString()))) }, { "{DATA}", Convert.ToBase64String(data) }, { "{POPULATED}", populated.ToString().ToLowerInvariant() } // Defaults to XML-friendly values }; var templateText = LoadTemplateText(out var templateRelativePath); if (templateText != null) { var outfileText = templateText; // Apply the parameters to the template foreach (var pair in substitutionDictionary) { outfileText = outfileText.Replace(pair.Key, pair.Value); } Directory.CreateDirectory(TangleFileConsts.k_OutputPath); File.WriteAllText(FullPathForTangleClass(classnamePrefix), outfileText); } } /// /// Loads the template file. /// /// The template file's text. /// Relative Assets/ path to template file. private static string LoadTemplateText(out string templateRelativePath) { var assetGUIDs = AssetDatabase.FindAssets(m_GeneratedCredentialsTemplateFilenameNoExtension); string templateGUID = null; templateRelativePath = null; if (assetGUIDs.Length > 0) { templateGUID = assetGUIDs[0]; } else { Debug.LogError(string.Format("Could not find template \"{0}\"", m_GeneratedCredentialsTemplateFilename)); } string templateText = null; if (templateGUID != null) { templateRelativePath = AssetDatabase.GUIDToAssetPath(templateGUID); var templateAbsolutePath = Path.GetDirectoryName(Application.dataPath) + Path.DirectorySeparatorChar + templateRelativePath; templateText = File.ReadAllText(templateAbsolutePath); } return templateText; } } } #endif ================================================ FILE: VirtueSky/Iap/Editor/ObfuscationGenerator.cs.meta ================================================ fileFormatVersion: 2 guid: ec3ca9e8aabd499eb4a3cba5aa6b34c4 timeCreated: 1697512782 ================================================ FILE: VirtueSky/Iap/Editor/TangleFileConsts.cs ================================================ #if UNITY_EDITOR namespace VirtueSky.Iap { public class TangleFileConsts { internal const string k_OutputPath = "Assets/_Sunflower/Scripts/UnityPurchasing/generated"; internal const string k_AppleClassPrefix = "Apple"; internal const string k_AppleStoreKitTestClassPrefix = "AppleStoreKitTest"; internal const string k_GooglePlayClassPrefix = "GooglePlay"; internal const string k_ObfuscationClassSuffix = "Tangle.cs"; } } #endif ================================================ FILE: VirtueSky/Iap/Editor/TangleFileConsts.cs.meta ================================================ fileFormatVersion: 2 guid: ab500741417a4e52a5809cb90bf12e56 timeCreated: 1697512817 ================================================ FILE: VirtueSky/Iap/Editor/TangleObfuscator.cs ================================================ #if UNITY_EDITOR using System; using System.Linq; namespace VirtueSky.Iap { public static class TangleObfuscator { /// /// An Exception thrown when the tangle order array provided is invalid or shorter than the number of data slices made. /// public class InvalidOrderArray : Exception { } /// /// Generates the obfucscation tangle data. /// /// The Apple or GooglePlay public key data to be obfuscated. /// The array, passed by reference, of order of the data slices used to obfuscate the data with. /// Outputs the encryption key to deobfuscate the tangled data at runtime /// The obfucated public key public static byte[] Obfuscate(byte[] data, int[] order, out int rkey) { var rnd = new System.Random(); var key = rnd.Next(2, 255); var res = new byte[data.Length]; var slices = data.Length / 20 + 1; if (order == null || order.Length < slices) { throw new InvalidOrderArray(); } Array.Copy(data, res, data.Length); for (var i = 0; i < slices - 1; i++) { var j = rnd.Next(i, slices - 1); order[i] = j; var sliceSize = 20; // prob should be configurable var tmp = res.Skip(i * 20).Take(sliceSize).ToArray(); // tmp = res[i*20 .. slice] Array.Copy(res, j * 20, res, i * 20, sliceSize); // res[i] = res[j*20 .. slice] Array.Copy(tmp, 0, res, j * 20, sliceSize); // res[j] = tmp } order[slices - 1] = slices - 1; rkey = key; return res.Select(x => (byte)(x ^ key)).ToArray(); } } } #endif ================================================ FILE: VirtueSky/Iap/Editor/TangleObfuscator.cs.meta ================================================ fileFormatVersion: 2 guid: 37539c07e6d2407bb3da42442654c120 timeCreated: 1697512870 ================================================ FILE: VirtueSky/Iap/Editor/Virtusky.Sunflower.Iap.Editor.asmdef ================================================ { "name": "Virtusky.Sunflower.Iap.Editor", "rootNamespace": "", "references": [ "GUID:0566ef25681cb4cec8714d50dda26ad1", "GUID:c904f6d969e991d459a0843b71c22ec5", "GUID:60bfecf5cb232594891bc622f40d6bed", "GUID:bd40169efe8642149b1d2b72ba4903ce", "GUID:acb3cac55c622ec459c8caadf707623a", "GUID:324caed91501a9c47a04ebfd87b68794", "GUID:0b6289df6f84a6f4b982ff72d23e0273" ], "includePlatforms": [ "Editor" ], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], "versionDefines": [], "noEngineReferences": false } ================================================ FILE: VirtueSky/Iap/Editor/Virtusky.Sunflower.Iap.Editor.asmdef.meta ================================================ fileFormatVersion: 2 guid: 405e8b335a1c8114fb36942b7f97083f AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Iap/Editor.meta ================================================ fileFormatVersion: 2 guid: 90fc5ff7994c4925afac4c80fe45572f timeCreated: 1697194680 ================================================ FILE: VirtueSky/Iap/Runtime/IapDataVariable.cs ================================================ #if VIRTUESKY_IAP using System; using System.Threading.Tasks; using Cysharp.Threading.Tasks; using UnityEngine; using UnityEngine.Purchasing; using VirtueSky.Inspector; namespace VirtueSky.Iap { [Serializable] [EditorIcon("scriptable_iap")] public class IapDataVariable : ScriptableObject { [ReadOnly] public string androidId; [ReadOnly] public string iosId; [ReadOnly] public ProductType productType; [Tooltip("Price config used for UI"), Space] public float priceConfig; [SerializeField] private IapPurchaseSuccess onPurchaseSuccess; [SerializeField] private IapPurchaseFailed onPurchaseFailed; internal IapPurchaseSuccess OnPurchaseSuccess => onPurchaseSuccess; internal IapPurchaseFailed OnPurchaseFailed => onPurchaseFailed; [NonSerialized] public Action purchaseSuccessCallback; [NonSerialized] public Action purchaseFailedCallback; private IapManager iapManager; public string Id { get { #if UNITY_ANDROID return androidId; #elif UNITY_IOS return iosId; #else return string.Empty; #endif } } internal void InitIapManager(IapManager _iapManager) { iapManager = _iapManager; } public Product GetProduct() { if (iapManager == null) return null; return iapManager.GetProduct(this); } public SubscriptionInfo GetSubscriptionInfo() { if (iapManager == null) return null; return iapManager.GetSubscriptionInfo(this); } public void Purchase() { if (iapManager == null) return; iapManager.PurchaseProduct(this); } public bool IsPurchased() { if (iapManager == null) return false; return iapManager.IsPurchasedProduct(this); } public string GetLocalizedPriceString() { if (GetProduct() == null) return String.Empty; return GetProduct().metadata.localizedPriceString; } public string GetIsoCurrencyCode() { if (GetProduct() == null) return String.Empty; return GetProduct().metadata.isoCurrencyCode; } public string GetLocalizedDescription() { if (GetProduct() == null) return String.Empty; return GetProduct().metadata.localizedDescription; } public string GetLocalizedTitle() { if (GetProduct() == null) return String.Empty; return GetProduct().metadata.localizedTitle; } public decimal GetLocalizedPrice() { if (GetProduct() == null) return 0; return GetProduct().metadata.localizedPrice; } } } #endif ================================================ FILE: VirtueSky/Iap/Runtime/IapDataVariable.cs.meta ================================================ fileFormatVersion: 2 guid: 40a793fde2834e079aa3418f036b9e09 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: a7c0b6e003e41ca408cabaf952160992, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Iap/Runtime/IapManager.cs ================================================ #if VIRTUESKY_IAP using System; using Cysharp.Threading.Tasks; using UnityEngine; using UnityEngine.Purchasing; using UnityEngine.Purchasing.Extension; using VirtueSky.Core; using VirtueSky.Events; using VirtueSky.Inspector; using VirtueSky.Misc; #if UNITY_EDITOR using VirtueSky.UtilsEditor; #endif namespace VirtueSky.Iap { [EditorIcon("icon_controller"), HideMonoScript] public class IapManager : BaseMono, IDetailedStoreListener { [Space] [SerializeField] private bool dontDestroyOnLoad = false; [Tooltip("Require"), SerializeField] private IapSetting iapSetting; [Tooltip("Allows nulls"), SerializeField] private BooleanEvent changePreventDisplayAppOpenEvent; private IStoreController _controller; private IExtensionProvider _extensionProvider; private static event Action RestoreEvent; public static event Func CustomValidatePurchaseEvent; public static bool IsInitialized { get; private set; } public static void Restore() => RestoreEvent?.Invoke(); private void Awake() { if (dontDestroyOnLoad) { DontDestroyOnLoad(this.gameObject); } } public override void OnEnable() { base.OnEnable(); #if UNITY_IOS RestoreEvent += RestorePurchase; #endif } public override void OnDisable() { base.OnDisable(); #if UNITY_IOS RestoreEvent -= RestorePurchase; #endif } private void Start() { Init(); } private async void Init() { if (IsInitialized) return; await UniTask.WaitUntil(() => UnityServiceInitialization.IsUnityServiceReady); var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance()); RequestProductData(builder); builder.Configure(); UnityPurchasing.Initialize(this, builder); } #region Internal Api internal bool IsPurchasedProduct(IapDataVariable product) { if (_controller == null) return false; return product.productType is ProductType.NonConsumable or ProductType.Subscription && _controller.products.WithID(product.Id).hasReceipt; } internal void PurchaseProduct(IapDataVariable product) { if (changePreventDisplayAppOpenEvent != null) changePreventDisplayAppOpenEvent.Raise(true); PurchaseProductInternal(product); } internal Product GetProduct(IapDataVariable product) { if (_controller == null) return null; return _controller.products.WithID(product.Id); } internal SubscriptionInfo GetSubscriptionInfo(IapDataVariable product) { if (_controller == null || product.productType != ProductType.Subscription || !_controller.products.WithID(product.Id).hasReceipt) return null; var subscriptionManager = new SubscriptionManager(GetProduct(product), null); var subscriptionInfo = subscriptionManager.getSubscriptionInfo(); return subscriptionInfo; } #endregion #region Implement public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs purchaseEvent) { if (iapSetting.IsValidatePurchase) { if (iapSetting.IsCustomValidatePurchase) { if ((bool)CustomValidatePurchaseEvent?.Invoke()) PurchaseVerified(purchaseEvent); } else { bool validatedPurchase = true; #if (UNITY_ANDROID || UNITY_IOS || UNITY_STANDALONE_OSX) && !UNITY_EDITOR var validator = new UnityEngine.Purchasing.Security.CrossPlatformValidator( UnityEngine.Purchasing.Security.GooglePlayTangle.Data(), UnityEngine.Purchasing.Security.AppleTangle.Data(), Application.identifier); try { // On Google Play, result has a single product ID. // On Apple stores, receipts contain multiple products. var result = validator.Validate(purchaseEvent.purchasedProduct.receipt); Debug.Log("Receipt is valid"); } catch (UnityEngine.Purchasing.Security.IAPSecurityException) { Debug.Log("Invalid receipt, not unlocking content"); validatedPurchase = false; } #endif if (validatedPurchase) PurchaseVerified(purchaseEvent); } } else { PurchaseVerified(purchaseEvent); } return PurchaseProcessingResult.Complete; } public void OnInitialized(IStoreController controller, IExtensionProvider extensions) { _controller = controller; _extensionProvider = extensions; foreach (var iapDataVariable in iapSetting.Products) { iapDataVariable.InitIapManager(this); } IsInitialized = true; } public void OnInitializeFailed(InitializationFailureReason error, string message) { OnInitializeFailed(error); } public void OnInitializeFailed(InitializationFailureReason error) { switch (error) { case InitializationFailureReason.AppNotKnown: Debug.LogError("Is your App correctly uploaded on the relevant publisher console?"); break; case InitializationFailureReason.PurchasingUnavailable: Debug.LogWarning("In App Purchases disabled in device settings!"); break; case InitializationFailureReason.NoProductsAvailable: Debug.LogWarning("No products available for purchase!"); break; default: throw new ArgumentOutOfRangeException(nameof(error), error, null); } } public void OnPurchaseFailed(Product product, PurchaseFailureReason failureReason) { InternalPurchaseFailed(product.definition.id, failureReason.ToString()); } public void OnPurchaseFailed(Product product, PurchaseFailureDescription failureDescription) { InternalPurchaseFailed(product.definition.id, failureDescription.reason.ToString()); } #endregion private IapDataVariable PurchaseProductInternal(IapDataVariable product) { #if (UNITY_ANDROID || UNITY_IOS) && !UNITY_EDITOR _controller?.InitiatePurchase(product.Id); #elif UNITY_EDITOR InternalPurchaseSuccess(product.Id); #endif return product; } void PurchaseVerified(PurchaseEventArgs purchaseEvent) { if (changePreventDisplayAppOpenEvent != null) changePreventDisplayAppOpenEvent.Raise(false); InternalPurchaseSuccess(purchaseEvent.purchasedProduct.definition.id); } #region Purchase Success void InternalPurchaseSuccess(string id) { foreach (var product in iapSetting.Products) { if (product.Id != id) continue; product.OnPurchaseSuccess.Raise(); Common.CallActionAndClean(ref product.purchaseSuccessCallback); } } #endregion #region Purchase Failed private void InternalPurchaseFailed(string id, string reason) { if (changePreventDisplayAppOpenEvent != null) changePreventDisplayAppOpenEvent.Raise(false); foreach (var product in iapSetting.Products) { if (product.Id != id) continue; product.OnPurchaseFailed.Raise(reason); Common.CallActionAndClean(ref product.purchaseFailedCallback, reason); } } #endregion private void RequestProductData(ConfigurationBuilder builder) { foreach (var p in iapSetting.Products) { builder.AddProduct(p.Id, p.productType); } } #if UNITY_IOS internal void RestorePurchase() { if (!IsInitialized) { Debug.Log("Restore purchases fail. not initialized!"); return; } if (Application.platform == RuntimePlatform.IPhonePlayer || Application.platform == RuntimePlatform.OSXPlayer) { Debug.Log("Restore purchase started ..."); var storeProvider = _extensionProvider.GetExtension(); storeProvider.RestoreTransactions((b, s) => { // no purchase are avaiable to restore Debug.Log($"Restore purchase continuing: {b}. If no further messages, no purchase available to restore."); }); } else { Debug.Log("Restore purchase fail. not supported on this platform. current = " + Application.platform); } } #endif #if UNITY_EDITOR private void Reset() { iapSetting = CreateAsset.CreateAndGetScriptableAsset("/Iap/Setting"); } #endif } } #endif ================================================ FILE: VirtueSky/Iap/Runtime/IapManager.cs.meta ================================================ fileFormatVersion: 2 guid: f80248d204b22674aa29ee9bc08e5df8 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 1c63e3b6583d6b54a8de6efcd2a86725, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Iap/Runtime/IapPurchaseFailed.cs ================================================ #if VIRTUESKY_IAP using UnityEngine; namespace VirtueSky.Iap { public abstract class IapPurchaseFailed : ScriptableObject { public abstract void Raise(string reason); } } #endif ================================================ FILE: VirtueSky/Iap/Runtime/IapPurchaseFailed.cs.meta ================================================ fileFormatVersion: 2 guid: af820398821940e9937c417e16be949e timeCreated: 1697447748 ================================================ FILE: VirtueSky/Iap/Runtime/IapPurchaseSuccess.cs ================================================ #if VIRTUESKY_IAP using UnityEngine; namespace VirtueSky.Iap { public abstract class IapPurchaseSuccess : ScriptableObject { public abstract void Raise(); } } #endif ================================================ FILE: VirtueSky/Iap/Runtime/IapPurchaseSuccess.cs.meta ================================================ fileFormatVersion: 2 guid: 15b5e3eb49fb4a89a05254636725a8c3 timeCreated: 1697447681 ================================================ FILE: VirtueSky/Iap/Runtime/IapSetting.cs ================================================ #if VIRTUESKY_IAP using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.Purchasing; using VirtueSky.Inspector; namespace VirtueSky.Iap { [EditorIcon("icon_scriptable")] public class IapSetting : ScriptableObject { [SerializeField] private List skusData = new List(); [SerializeField] private List products = new List(); [Space, SerializeField] private bool isValidatePurchase; [SerializeField] private bool isCustomValidatePurchase; #if UNITY_EDITOR //[ShowIf(nameof(isValidatePurchase), true)] [SerializeField, TextArea] private string googlePlayStoreKey; public string GooglePlayStoreKey => googlePlayStoreKey; #endif public List SkusData => skusData; public List Products => products; public bool IsValidatePurchase => isValidatePurchase; public bool IsCustomValidatePurchase => isCustomValidatePurchase; } [Serializable] public class IapData { public string androidId; public string iosId; public string customProductName; public string Id { get { #if UNITY_ANDROID return androidId; #elif UNITY_IOS return iosId; #else return string.Empty; #endif } } public ProductType productType; } } #endif ================================================ FILE: VirtueSky/Iap/Runtime/IapSetting.cs.meta ================================================ fileFormatVersion: 2 guid: 8860d8e8b438431b873695abf0f12215 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: ed5ec0bb4ec55df47af0ecc2bd7be5f9, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Iap/Runtime/IapStatic.cs ================================================ #if VIRTUESKY_IAP using System; using VirtueSky.Events; namespace VirtueSky.Iap { public static class IapStatic { public static IapDataVariable OnPurchaseCompleted(this IapDataVariable product, Action onComplete) { product.purchaseSuccessCallback = onComplete; return product; } public static IapDataVariable OnPurchaseFailed(this IapDataVariable product, Action onFailed) { product.purchaseFailedCallback = onFailed; return product; } } } #endif ================================================ FILE: VirtueSky/Iap/Runtime/IapStatic.cs.meta ================================================ fileFormatVersion: 2 guid: 7ed5bcb6183b4ba082116c7095bc334e timeCreated: 1697448017 ================================================ FILE: VirtueSky/Iap/Runtime/Virtusky.Sunflower.Iap.asmdef ================================================ { "name": "Virtusky.Sunflower.Iap", "rootNamespace": "", "references": [ "GUID:bd40169efe8642149b1d2b72ba4903ce", "GUID:acb3cac55c622ec459c8caadf707623a", "GUID:60bfecf5cb232594891bc622f40d6bed", "GUID:94e1de2458b07d0bf1e9f13e6ae06443", "GUID:e63a64384cc3ef04cac761c1ce76e9c2", "GUID:d0bf1e9f644394e1de13e6ae02458b07", "GUID:08d1c582746949b40ba6a45cdb776bdf", "GUID:fca7ec166e04dc948b624a983315e2c9", "GUID:a90b00dc83a89964cb7641c304492d29", "GUID:c904f6d969e991d459a0843b71c22ec5", "GUID:324caed91501a9c47a04ebfd87b68794", "GUID:f51ebe6a0ceec4240a699833d6309b23" ], "includePlatforms": [], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], "versionDefines": [ { "name": "com.unity.purchasing", "expression": "4.11.0", "define": "VIRTUESKY_IAP" } ], "noEngineReferences": false } ================================================ FILE: VirtueSky/Iap/Runtime/Virtusky.Sunflower.Iap.asmdef.meta ================================================ fileFormatVersion: 2 guid: 0566ef25681cb4cec8714d50dda26ad1 AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Iap/Runtime.meta ================================================ fileFormatVersion: 2 guid: 6f2773e8e5742d14aa9914c2564e2aa2 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Iap.meta ================================================ fileFormatVersion: 2 guid: 84a07bffd2183af498eeb05c1a93628f folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Inspector/.editorconfig ================================================ [*] charset = utf-8 end_of_line = crlf trim_trailing_whitespace = false insert_final_newline = false indent_style = space indent_size = 4 # Microsoft .NET properties csharp_indent_braces = false csharp_indent_switch_labels = true csharp_new_line_before_catch = true csharp_new_line_before_else = true csharp_new_line_before_finally = true csharp_new_line_before_members_in_object_initializers = false csharp_new_line_before_open_brace = all csharp_new_line_between_query_expression_clauses = true csharp_preferred_modifier_order = public, private, protected, internal, new, abstract, virtual, sealed, override, static, readonly, extern, unsafe, volatile, async:suggestion csharp_preserve_single_line_blocks = true csharp_space_after_cast = true csharp_space_after_colon_in_inheritance_clause = true csharp_space_after_comma = true csharp_space_after_dot = false csharp_space_after_keywords_in_control_flow_statements = true csharp_space_after_semicolon_in_for_statement = true csharp_space_around_binary_operators = before_and_after csharp_space_before_colon_in_inheritance_clause = true csharp_space_before_comma = false csharp_space_before_dot = false csharp_space_before_open_square_brackets = false csharp_space_before_semicolon_in_for_statement = false csharp_space_between_empty_square_brackets = false csharp_space_between_method_call_empty_parameter_list_parentheses = false csharp_space_between_method_call_name_and_opening_parenthesis = false csharp_space_between_method_call_parameter_list_parentheses = false csharp_space_between_method_declaration_empty_parameter_list_parentheses = false csharp_space_between_method_declaration_name_and_open_parenthesis = false csharp_space_between_method_declaration_parameter_list_parentheses = false csharp_space_between_parentheses = false csharp_space_between_square_brackets = false csharp_style_var_elsewhere = true:suggestion csharp_style_var_for_built_in_types = true:suggestion csharp_style_var_when_type_is_apparent = true:suggestion csharp_using_directive_placement = outside_namespace:silent dotnet_naming_rule.constants_rule.severity = warning dotnet_naming_rule.constants_rule.style = upper_camel_case_style dotnet_naming_rule.constants_rule.symbols = constants_symbols dotnet_naming_rule.event_rule.severity = warning dotnet_naming_rule.event_rule.style = upper_camel_case_style dotnet_naming_rule.event_rule.symbols = event_symbols dotnet_naming_rule.interfaces_rule.severity = warning dotnet_naming_rule.interfaces_rule.style = i_upper_camel_case_style dotnet_naming_rule.interfaces_rule.symbols = interfaces_symbols dotnet_naming_rule.locals_rule.severity = warning dotnet_naming_rule.locals_rule.style = lower_camel_case_style dotnet_naming_rule.locals_rule.symbols = locals_symbols dotnet_naming_rule.local_constants_rule.severity = warning dotnet_naming_rule.local_constants_rule.style = lower_camel_case_style dotnet_naming_rule.local_constants_rule.symbols = local_constants_symbols dotnet_naming_rule.local_functions_rule.severity = warning dotnet_naming_rule.local_functions_rule.style = upper_camel_case_style dotnet_naming_rule.local_functions_rule.symbols = local_functions_symbols dotnet_naming_rule.method_rule.severity = warning dotnet_naming_rule.method_rule.style = upper_camel_case_style dotnet_naming_rule.method_rule.symbols = method_symbols dotnet_naming_rule.parameters_rule.severity = warning dotnet_naming_rule.parameters_rule.style = lower_camel_case_style dotnet_naming_rule.parameters_rule.symbols = parameters_symbols dotnet_naming_rule.private_constants_rule.severity = warning dotnet_naming_rule.private_constants_rule.style = upper_camel_case_style dotnet_naming_rule.private_constants_rule.symbols = private_constants_symbols dotnet_naming_rule.private_instance_fields_rule.severity = warning dotnet_naming_rule.private_instance_fields_rule.style = lower_camel_case_style_1 dotnet_naming_rule.private_instance_fields_rule.symbols = private_instance_fields_symbols dotnet_naming_rule.private_static_fields_rule.severity = warning dotnet_naming_rule.private_static_fields_rule.style = lower_camel_case_style_1 dotnet_naming_rule.private_static_fields_rule.symbols = private_static_fields_symbols dotnet_naming_rule.private_static_readonly_rule.severity = warning dotnet_naming_rule.private_static_readonly_rule.style = upper_camel_case_style dotnet_naming_rule.private_static_readonly_rule.symbols = private_static_readonly_symbols dotnet_naming_rule.property_rule.severity = warning dotnet_naming_rule.property_rule.style = upper_camel_case_style dotnet_naming_rule.property_rule.symbols = property_symbols dotnet_naming_rule.public_fields_rule.severity = warning dotnet_naming_rule.public_fields_rule.style = lower_camel_case_style dotnet_naming_rule.public_fields_rule.symbols = public_fields_symbols dotnet_naming_rule.static_readonly_rule.severity = warning dotnet_naming_rule.static_readonly_rule.style = upper_camel_case_style dotnet_naming_rule.static_readonly_rule.symbols = static_readonly_symbols dotnet_naming_rule.types_and_namespaces_rule.severity = warning dotnet_naming_rule.types_and_namespaces_rule.style = upper_camel_case_style dotnet_naming_rule.types_and_namespaces_rule.symbols = types_and_namespaces_symbols dotnet_naming_rule.type_parameters_rule.severity = warning dotnet_naming_rule.type_parameters_rule.style = t_upper_camel_case_style dotnet_naming_rule.type_parameters_rule.symbols = type_parameters_symbols dotnet_naming_style.i_upper_camel_case_style.capitalization = pascal_case dotnet_naming_style.i_upper_camel_case_style.required_prefix = I dotnet_naming_style.lower_camel_case_style.capitalization = camel_case dotnet_naming_style.lower_camel_case_style_1.capitalization = camel_case dotnet_naming_style.lower_camel_case_style_1.required_prefix = _ dotnet_naming_style.t_upper_camel_case_style.capitalization = pascal_case dotnet_naming_style.t_upper_camel_case_style.required_prefix = T dotnet_naming_style.upper_camel_case_style.capitalization = pascal_case dotnet_naming_symbols.constants_symbols.applicable_accessibilities = public,internal,protected,protected_internal,private_protected dotnet_naming_symbols.constants_symbols.applicable_kinds = field dotnet_naming_symbols.constants_symbols.required_modifiers = const dotnet_naming_symbols.event_symbols.applicable_accessibilities = * dotnet_naming_symbols.event_symbols.applicable_kinds = event dotnet_naming_symbols.interfaces_symbols.applicable_accessibilities = * dotnet_naming_symbols.interfaces_symbols.applicable_kinds = interface dotnet_naming_symbols.locals_symbols.applicable_accessibilities = * dotnet_naming_symbols.locals_symbols.applicable_kinds = local dotnet_naming_symbols.local_constants_symbols.applicable_accessibilities = * dotnet_naming_symbols.local_constants_symbols.applicable_kinds = local dotnet_naming_symbols.local_constants_symbols.required_modifiers = const dotnet_naming_symbols.local_functions_symbols.applicable_accessibilities = * dotnet_naming_symbols.local_functions_symbols.applicable_kinds = local_function dotnet_naming_symbols.method_symbols.applicable_accessibilities = * dotnet_naming_symbols.method_symbols.applicable_kinds = method dotnet_naming_symbols.parameters_symbols.applicable_accessibilities = * dotnet_naming_symbols.parameters_symbols.applicable_kinds = parameter dotnet_naming_symbols.private_constants_symbols.applicable_accessibilities = private dotnet_naming_symbols.private_constants_symbols.applicable_kinds = field dotnet_naming_symbols.private_constants_symbols.required_modifiers = const dotnet_naming_symbols.private_instance_fields_symbols.applicable_accessibilities = private dotnet_naming_symbols.private_instance_fields_symbols.applicable_kinds = field dotnet_naming_symbols.private_static_fields_symbols.applicable_accessibilities = private dotnet_naming_symbols.private_static_fields_symbols.applicable_kinds = field dotnet_naming_symbols.private_static_fields_symbols.required_modifiers = static dotnet_naming_symbols.private_static_readonly_symbols.applicable_accessibilities = private dotnet_naming_symbols.private_static_readonly_symbols.applicable_kinds = field dotnet_naming_symbols.private_static_readonly_symbols.required_modifiers = static,readonly dotnet_naming_symbols.property_symbols.applicable_accessibilities = * dotnet_naming_symbols.property_symbols.applicable_kinds = property dotnet_naming_symbols.public_fields_symbols.applicable_accessibilities = public,internal,protected,protected_internal,private_protected dotnet_naming_symbols.public_fields_symbols.applicable_kinds = field dotnet_naming_symbols.static_readonly_symbols.applicable_accessibilities = public,internal,protected,protected_internal,private_protected dotnet_naming_symbols.static_readonly_symbols.applicable_kinds = field dotnet_naming_symbols.static_readonly_symbols.required_modifiers = static,readonly dotnet_naming_symbols.types_and_namespaces_symbols.applicable_accessibilities = * dotnet_naming_symbols.types_and_namespaces_symbols.applicable_kinds = namespace,class,struct,enum,delegate dotnet_naming_symbols.type_parameters_symbols.applicable_accessibilities = * dotnet_naming_symbols.type_parameters_symbols.applicable_kinds = type_parameter dotnet_separate_import_directive_groups = false dotnet_sort_system_directives_first = true dotnet_style_parentheses_in_arithmetic_binary_operators = never_if_unnecessary:none dotnet_style_parentheses_in_other_binary_operators = never_if_unnecessary:none dotnet_style_parentheses_in_relational_binary_operators = never_if_unnecessary:none dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion dotnet_style_predefined_type_for_member_access = true:suggestion dotnet_style_qualification_for_event = false:suggestion dotnet_style_qualification_for_field = false:suggestion dotnet_style_qualification_for_method = false:suggestion dotnet_style_qualification_for_property = false:suggestion dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion file_header_template = # ReSharper properties resharper_accessor_owner_body = expression_body resharper_alignment_tab_fill_style = use_spaces resharper_align_first_arg_by_paren = false resharper_align_linq_query = false resharper_align_multiline_array_and_object_initializer = false resharper_align_multiline_array_initializer = true resharper_align_multiline_ctor_init = true resharper_align_multiline_expression_braces = false resharper_align_multiline_implements_list = true resharper_align_multiline_property_pattern = false resharper_align_multiline_switch_expression = false resharper_align_multiline_type_argument = true resharper_align_multiline_type_parameter = true resharper_align_multline_type_parameter_constrains = false resharper_align_multline_type_parameter_list = false resharper_align_ternary = align_not_nested resharper_align_tuple_components = false resharper_allow_alias = true resharper_allow_comment_after_lbrace = false resharper_allow_far_alignment = false resharper_always_use_end_of_line_brace_style = false resharper_anonymous_method_declaration_braces = next_line resharper_apply_auto_detected_rules = true resharper_apply_on_completion = false resharper_arguments_anonymous_function = positional resharper_arguments_literal = positional resharper_arguments_named = positional resharper_arguments_other = positional resharper_arguments_skip_single = false resharper_arguments_string_literal = positional resharper_attribute_style = do_not_touch resharper_autodetect_indent_settings = true resharper_blank_lines_after_block_statements = 1 resharper_blank_lines_after_case = 0 resharper_blank_lines_after_control_transfer_statements = 0 resharper_blank_lines_after_imports = 1 resharper_blank_lines_after_multiline_statements = 0 resharper_blank_lines_after_options = 1 resharper_blank_lines_after_start_comment = 1 resharper_blank_lines_after_using_list = 1 resharper_blank_lines_around_accessor = 0 resharper_blank_lines_around_auto_property = 1 resharper_blank_lines_around_block_case_section = 0 resharper_blank_lines_around_class_definition = 1 resharper_blank_lines_around_field = 1 resharper_blank_lines_around_function_declaration = 0 resharper_blank_lines_around_function_definition = 1 resharper_blank_lines_around_global_attribute = 0 resharper_blank_lines_around_invocable = 1 resharper_blank_lines_around_local_method = 1 resharper_blank_lines_around_multiline_case_section = 0 resharper_blank_lines_around_namespace = 1 resharper_blank_lines_around_other_declaration = 0 resharper_blank_lines_around_property = 1 resharper_blank_lines_around_razor_functions = 1 resharper_blank_lines_around_razor_helpers = 1 resharper_blank_lines_around_razor_sections = 1 resharper_blank_lines_around_region = 1 resharper_blank_lines_around_single_line_accessor = 0 resharper_blank_lines_around_single_line_auto_property = 0 resharper_blank_lines_around_single_line_field = 0 resharper_blank_lines_around_single_line_function_definition = 0 resharper_blank_lines_around_single_line_invocable = 0 resharper_blank_lines_around_single_line_local_method = 0 resharper_blank_lines_around_single_line_property = 0 resharper_blank_lines_around_single_line_type = 1 resharper_blank_lines_around_type = 1 resharper_blank_lines_before_block_statements = 0 resharper_blank_lines_before_case = 0 resharper_blank_lines_before_control_transfer_statements = 0 resharper_blank_lines_before_multiline_statements = 0 resharper_blank_lines_before_single_line_comment = 0 resharper_blank_lines_inside_namespace = 0 resharper_blank_lines_inside_region = 1 resharper_blank_lines_inside_type = 0 resharper_blank_line_after_pi = true resharper_braces_for_dowhile = required resharper_braces_for_fixed = required resharper_braces_for_for = required resharper_braces_for_foreach = required resharper_braces_for_ifelse = required resharper_braces_for_lock = required resharper_braces_for_using = required resharper_braces_for_while = required resharper_braces_redundant = false resharper_break_template_declaration = line_break resharper_can_use_global_alias = true resharper_constructor_or_destructor_body = block_body resharper_continuous_indent_multiplier = 1 resharper_continuous_line_indent = single resharper_cpp_align_multiline_argument = true resharper_cpp_align_multiline_binary_expressions_chain = false resharper_cpp_align_multiline_calls_chain = true resharper_cpp_align_multiline_extends_list = true resharper_cpp_align_multiline_for_stmt = true resharper_cpp_align_multiline_parameter = true resharper_cpp_align_multiple_declaration = true resharper_cpp_case_block_braces = next_line_shifted_2 resharper_cpp_indent_switch_labels = false resharper_cpp_max_line_length = 120 resharper_cpp_new_line_before_while = true resharper_cpp_space_after_cast = false resharper_cpp_space_around_binary_operator = true resharper_cpp_wrap_lines = true resharper_csharp_align_multiline_argument = false resharper_csharp_align_multiline_binary_expressions_chain = true resharper_csharp_align_multiline_calls_chain = false resharper_csharp_align_multiline_expression = false resharper_csharp_align_multiline_extends_list = false resharper_csharp_align_multiline_for_stmt = false resharper_csharp_align_multiline_parameter = false resharper_csharp_align_multiple_declaration = false resharper_csharp_max_line_length = 120 resharper_csharp_naming_rule.enum_member = AaBb resharper_csharp_naming_rule.method_property_event = AaBb resharper_csharp_naming_rule.other = AaBb resharper_csharp_naming_rule.public_fields = aaBb, AaBb resharper_csharp_new_line_before_while = false resharper_csharp_prefer_qualified_reference = false resharper_csharp_space_after_unary_operator = false resharper_csharp_wrap_lines = true resharper_cxxcli_property_declaration_braces = next_line resharper_default_exception_variable_name = e resharper_default_value_when_type_evident = default_literal resharper_default_value_when_type_not_evident = default_literal resharper_delete_quotes_from_solid_values = false resharper_disable_blank_line_changes = false resharper_disable_formatter = false resharper_disable_indenter = false resharper_disable_int_align = false resharper_disable_line_break_changes = false resharper_disable_line_break_removal = false resharper_disable_space_changes = false resharper_disable_space_changes_before_trailing_comment = false resharper_dont_remove_extra_blank_lines = false resharper_empty_block_style = multiline resharper_enable_wrapping = false resharper_enforce_line_ending_style = false resharper_event_handler_pattern_long = $object$On$event$ resharper_event_handler_pattern_short = On$event$ resharper_expression_braces = inside resharper_expression_pars = inside resharper_extra_spaces = remove_all resharper_force_attribute_style = separate resharper_force_chop_compound_do_expression = false resharper_force_chop_compound_if_expression = false resharper_force_chop_compound_while_expression = false resharper_format_leading_spaces_decl = false resharper_free_block_braces = next_line resharper_fsharp_align_function_signature_to_indentation = false resharper_fsharp_alternative_long_member_definitions = false resharper_fsharp_indent_on_try_with = false resharper_fsharp_keep_if_then_in_same_line = false resharper_fsharp_max_array_or_list_width = 40 resharper_fsharp_max_elmish_width = 40 resharper_fsharp_max_function_binding_width = 40 resharper_fsharp_max_if_then_else_short_width = 40 resharper_fsharp_max_infix_operator_expression = 50 resharper_fsharp_max_line_length = 120 resharper_fsharp_max_record_width = 40 resharper_fsharp_max_value_binding_width = 40 resharper_fsharp_multiline_block_brackets_on_same_column = false resharper_fsharp_newline_between_type_definition_and_members = false resharper_fsharp_semicolon_at_end_of_line = false resharper_fsharp_single_argument_web_mode = false resharper_fsharp_space_after_comma = true resharper_fsharp_space_after_semicolon = true resharper_fsharp_space_around_delimiter = true resharper_fsharp_space_before_class_constructor = false resharper_fsharp_space_before_colon = false resharper_fsharp_space_before_lowercase_invocation = true resharper_fsharp_space_before_member = false resharper_fsharp_space_before_parameter = true resharper_fsharp_space_before_semicolon = false resharper_fsharp_space_before_uppercase_invocation = false resharper_fsharp_wrap_lines = true resharper_function_declaration_return_type_style = do_not_change resharper_function_definition_return_type_style = do_not_change resharper_generator_mode = false resharper_html_attribute_indent = align_by_first_attribute resharper_html_linebreak_before_elements = body,div,p,form,h1,h2,h3 resharper_html_max_blank_lines_between_tags = 2 resharper_html_max_line_length = 120 resharper_html_pi_attribute_style = on_single_line resharper_html_space_before_self_closing = false resharper_html_wrap_lines = true resharper_ignore_space_preservation = false resharper_include_prefix_comment_in_indent = false resharper_indent_access_specifiers_from_class = false resharper_indent_aligned_ternary = true resharper_indent_anonymous_method_block = false resharper_indent_case_from_select = true resharper_indent_child_elements = OneIndent resharper_indent_class_members_from_access_specifiers = false resharper_indent_comment = true resharper_indent_inside_namespace = true resharper_indent_invocation_pars = inside resharper_indent_method_decl_pars = inside resharper_indent_nested_fixed_stmt = false resharper_indent_nested_foreach_stmt = false resharper_indent_nested_for_stmt = false resharper_indent_nested_lock_stmt = false resharper_indent_nested_usings_stmt = false resharper_indent_nested_while_stmt = false resharper_indent_pars = inside resharper_indent_preprocessor_directives = normal resharper_indent_preprocessor_if = no_indent resharper_indent_preprocessor_other = no_indent resharper_indent_preprocessor_region = usual_indent resharper_indent_statement_pars = inside resharper_indent_text = OneIndent resharper_indent_typearg_angles = inside resharper_indent_typeparam_angles = inside resharper_indent_type_constraints = true resharper_indent_wrapped_function_names = false resharper_instance_members_qualify_declared_in = this_class, base_class resharper_int_align = false resharper_int_align_comments = false resharper_int_align_declaration_names = false resharper_int_align_eq = false resharper_int_align_fix_in_adjacent = true resharper_invocable_declaration_braces = next_line resharper_keep_blank_lines_in_code = 2 resharper_keep_blank_lines_in_declarations = 2 resharper_keep_existing_attribute_arrangement = true resharper_keep_existing_declaration_block_arrangement = false resharper_keep_existing_declaration_parens_arrangement = true resharper_keep_existing_embedded_arrangement = true resharper_keep_existing_embedded_block_arrangement = false resharper_keep_existing_enum_arrangement = false resharper_keep_existing_expr_member_arrangement = true resharper_keep_existing_invocation_parens_arrangement = true resharper_keep_existing_property_patterns_arrangement = true resharper_keep_existing_switch_expression_arrangement = true resharper_keep_nontrivial_alias = true resharper_keep_user_linebreaks = true resharper_keep_user_wrapping = true resharper_linebreaks_around_razor_statements = true resharper_linebreaks_inside_tags_for_elements_longer_than = 2147483647 resharper_linebreaks_inside_tags_for_elements_with_child_elements = true resharper_linebreaks_inside_tags_for_multiline_elements = true resharper_linebreak_before_all_elements = false resharper_linebreak_before_multiline_elements = true resharper_linebreak_before_singleline_elements = false resharper_line_break_after_colon_in_member_initializer_lists = do_not_change resharper_line_break_after_comma_in_member_initializer_lists = false resharper_line_break_before_comma_in_member_initializer_lists = false resharper_linkage_specification_braces = end_of_line resharper_linkage_specification_indentation = none resharper_local_function_body = block_body resharper_max_array_initializer_elements_on_line = 10000 resharper_max_attribute_length_for_same_line = 38 resharper_max_enum_members_on_line = 3 resharper_max_formal_parameters_on_line = 10000 resharper_max_initializer_elements_on_line = 4 resharper_max_invocation_arguments_on_line = 10000 resharper_member_initializer_list_style = do_not_change resharper_method_or_operator_body = block_body resharper_namespace_declaration_braces = next_line resharper_namespace_indentation = all resharper_nested_ternary_style = autodetect resharper_never_outdent_pipe_operators = true resharper_new_line_before_catch = true resharper_new_line_before_else = true resharper_new_line_before_enumerators = true resharper_normalize_tag_names = false resharper_no_indent_inside_elements = html,body,thead,tbody,tfoot resharper_no_indent_inside_if_element_longer_than = 200 resharper_object_creation_when_type_evident = target_typed resharper_object_creation_when_type_not_evident = explicitly_typed resharper_old_engine = false resharper_other_braces = next_line resharper_outdent_binary_operators = true resharper_outdent_binary_ops = false resharper_outdent_commas = false resharper_outdent_dots = false resharper_outdent_namespace_member = false resharper_outdent_ternary_ops = false resharper_parentheses_non_obvious_operations = none, bitwise, bitwise_inclusive_or, bitwise_exclusive_or, shift, bitwise_and resharper_parentheses_redundancy_style = remove_if_not_clarifies_precedence resharper_pi_attributes_indent = align_by_first_attribute resharper_place_attribute_on_same_line = true resharper_place_comments_at_first_column = false resharper_place_constructor_initializer_on_same_line = true resharper_place_event_attribute_on_same_line = false resharper_place_expr_accessor_on_single_line = if_owner_is_single_line resharper_place_expr_method_on_single_line = if_owner_is_single_line resharper_place_expr_property_on_single_line = if_owner_is_single_line resharper_place_linq_into_on_new_line = true resharper_place_namespace_definitions_on_same_line = false resharper_place_property_attribute_on_same_line = false resharper_place_simple_case_statement_on_same_line = false resharper_place_simple_embedded_statement_on_same_line = if_owner_is_single_line resharper_place_simple_initializer_on_single_line = true resharper_place_simple_property_pattern_on_single_line = true resharper_place_simple_switch_expression_on_single_line = false resharper_place_type_constraints_on_same_line = true resharper_prefer_explicit_discard_declaration = false resharper_prefer_separate_deconstructed_variables_declaration = false resharper_preserve_spaces_inside_tags = pre,textarea resharper_qualified_using_at_nested_scope = false resharper_quote_style = doublequoted resharper_razor_prefer_qualified_reference = true resharper_remove_blank_lines_near_braces = false resharper_remove_blank_lines_near_braces_in_code = true resharper_remove_blank_lines_near_braces_in_declarations = true resharper_remove_this_qualifier = true resharper_requires_expression_braces = next_line resharper_resx_attribute_indent = single_indent resharper_resx_linebreak_before_elements = resharper_resx_max_blank_lines_between_tags = 0 resharper_resx_max_line_length = 2147483647 resharper_resx_pi_attribute_style = do_not_touch resharper_resx_space_before_self_closing = false resharper_resx_wrap_lines = false resharper_resx_wrap_tags_and_pi = false resharper_resx_wrap_text = false resharper_shaderlab_brace_style = next_line resharper_shaderlab_max_line_length = 120 resharper_shaderlab_wrap_lines = true resharper_show_autodetect_configure_formatting_tip = true resharper_simple_block_style = do_not_change resharper_simple_case_statement_style = do_not_change resharper_simple_embedded_statement_style = do_not_change resharper_sort_attributes = false resharper_sort_class_selectors = false resharper_sort_usings = true resharper_sort_usings_lowercase_first = false resharper_spaces_around_eq_in_attribute = false resharper_spaces_around_eq_in_pi_attribute = false resharper_spaces_inside_tags = false resharper_space_after_attributes = true resharper_space_after_attribute_target_colon = true resharper_space_after_colon = true resharper_space_after_colon_in_case = true resharper_space_after_colon_in_inheritance_clause = true resharper_space_after_comma = true resharper_space_after_for_colon = true resharper_space_after_keywords_in_control_flow_statements = true resharper_space_after_last_attribute = false resharper_space_after_last_pi_attribute = false resharper_space_after_operator_keyword = true resharper_space_after_ptr_in_data_member = true resharper_space_after_ptr_in_data_members = false resharper_space_after_ptr_in_method = true resharper_space_after_ref_in_data_member = true resharper_space_after_ref_in_data_members = false resharper_space_after_ref_in_method = true resharper_space_after_semicolon_in_for_statement = true resharper_space_after_ternary_colon = true resharper_space_after_ternary_quest = true resharper_space_after_triple_slash = true resharper_space_after_type_parameter_constraint_colon = true resharper_space_around_additive_op = true resharper_space_around_alias_eq = true resharper_space_around_assignment_op = true resharper_space_around_assignment_operator = true resharper_space_around_deref_in_trailing_return_type = true resharper_space_around_lambda_arrow = true resharper_space_around_member_access_operator = false resharper_space_around_relational_op = true resharper_space_around_shift_op = true resharper_space_around_stmt_colon = true resharper_space_around_ternary_operator = true resharper_space_before_array_rank_parentheses = false resharper_space_before_attribute_target_colon = false resharper_space_before_checked_parentheses = false resharper_space_before_colon = false resharper_space_before_colon_in_case = false resharper_space_before_colon_in_inheritance_clause = true resharper_space_before_comma = false resharper_space_before_default_parentheses = false resharper_space_before_empty_invocation_parentheses = false resharper_space_before_empty_method_parentheses = false resharper_space_before_for_colon = true resharper_space_before_initializer_braces = false resharper_space_before_invocation_parentheses = false resharper_space_before_label_colon = false resharper_space_before_lambda_parentheses = false resharper_space_before_method_parentheses = false resharper_space_before_nameof_parentheses = false resharper_space_before_nullable_mark = false resharper_space_before_open_square_brackets = false resharper_space_before_pointer_asterik_declaration = false resharper_space_before_ptr_in_abstract_decl = false resharper_space_before_ptr_in_data_member = false resharper_space_before_ptr_in_data_members = true resharper_space_before_ptr_in_method = false resharper_space_before_ref_in_abstract_decl = false resharper_space_before_ref_in_data_member = false resharper_space_before_ref_in_data_members = true resharper_space_before_ref_in_method = false resharper_space_before_semicolon = false resharper_space_before_semicolon_in_for_statement = false resharper_space_before_singleline_accessorholder = true resharper_space_before_sizeof_parentheses = false resharper_space_before_template_args = false resharper_space_before_template_params = true resharper_space_before_ternary_colon = true resharper_space_before_ternary_quest = true resharper_space_before_trailing_comment = true resharper_space_before_typeof_parentheses = false resharper_space_before_type_argument_angle = false resharper_space_before_type_parameter_angle = false resharper_space_before_type_parameter_constraint_colon = true resharper_space_before_type_parameter_parentheses = true resharper_space_between_accessors_in_singleline_property = true resharper_space_between_attribute_sections = true resharper_space_between_closing_angle_brackets_in_template_args = false resharper_space_between_keyword_and_expression = true resharper_space_between_keyword_and_type = true resharper_space_between_method_call_empty_parameter_list_parentheses = false resharper_space_between_method_call_name_and_opening_parenthesis = false resharper_space_between_method_call_parameter_list_parentheses = false resharper_space_between_method_declaration_empty_parameter_list_parentheses = false resharper_space_between_method_declaration_name_and_open_parenthesis = false resharper_space_between_method_declaration_parameter_list_parentheses = false resharper_space_between_parentheses_of_control_flow_statements = false resharper_space_between_square_brackets = false resharper_space_between_typecast_parentheses = false resharper_space_in_singleline_accessorholder = true resharper_space_in_singleline_anonymous_method = true resharper_space_in_singleline_method = true resharper_space_near_postfix_and_prefix_op = false resharper_space_within_array_initialization_braces = false resharper_space_within_array_rank_empty_parentheses = false resharper_space_within_array_rank_parentheses = false resharper_space_within_attribute_angles = false resharper_space_within_checked_parentheses = false resharper_space_within_default_parentheses = false resharper_space_within_empty_braces = true resharper_space_within_empty_initializer_braces = false resharper_space_within_empty_invocation_parentheses = false resharper_space_within_empty_method_parentheses = false resharper_space_within_empty_template_params = false resharper_space_within_expression_parentheses = false resharper_space_within_initializer_braces = false resharper_space_within_invocation_parentheses = false resharper_space_within_method_parentheses = false resharper_space_within_nameof_parentheses = false resharper_space_within_parentheses = false resharper_space_within_single_line_array_initializer_braces = false resharper_space_within_sizeof_parentheses = false resharper_space_within_template_args = false resharper_space_within_template_params = false resharper_space_within_tuple_parentheses = false resharper_space_within_typeof_parentheses = false resharper_space_within_type_argument_angles = false resharper_space_within_type_parameter_angles = false resharper_space_within_type_parameter_parentheses = false resharper_special_else_if_treatment = true resharper_static_members_qualify_members = none resharper_static_members_qualify_with = declared_type resharper_stick_comment = true resharper_support_vs_event_naming_pattern = true resharper_toplevel_function_declaration_return_type_style = do_not_change resharper_toplevel_function_definition_return_type_style = do_not_change resharper_trailing_comma_in_multiline_lists = true resharper_trailing_comma_in_singleline_lists = true resharper_type_declaration_braces = next_line resharper_use_continuous_indent_inside_initializer_braces = true resharper_use_continuous_indent_inside_parens = true resharper_use_continuous_line_indent_in_expression_braces = false resharper_use_continuous_line_indent_in_method_pars = false resharper_use_heuristics_for_body_style = true resharper_use_indents_from_main_language_in_file = true resharper_use_indent_from_previous_element = true resharper_use_indent_from_vs = false resharper_use_roslyn_logic_for_evident_types = false resharper_vb_align_multiline_argument = true resharper_vb_align_multiline_expression = true resharper_vb_align_multiline_parameter = true resharper_vb_align_multiple_declaration = true resharper_vb_max_line_length = 120 resharper_vb_place_field_attribute_on_same_line = true resharper_vb_place_method_attribute_on_same_line = false resharper_vb_place_type_attribute_on_same_line = false resharper_vb_prefer_qualified_reference = false resharper_vb_space_after_unary_operator = true resharper_vb_space_around_multiplicative_op = false resharper_vb_wrap_lines = true resharper_wrap_after_binary_opsign = true resharper_wrap_after_declaration_lpar = false resharper_wrap_after_dot = false resharper_wrap_after_dot_in_method_calls = false resharper_wrap_after_expression_lbrace = true resharper_wrap_after_invocation_lpar = false resharper_wrap_arguments_style = wrap_if_long resharper_wrap_around_elements = true resharper_wrap_array_initializer_style = wrap_if_long resharper_wrap_base_clause_style = wrap_if_long resharper_wrap_before_arrow_with_expressions = false resharper_wrap_before_binary_opsign = false resharper_wrap_before_colon = false resharper_wrap_before_comma = false resharper_wrap_before_comma_in_base_clause = false resharper_wrap_before_declaration_lpar = false resharper_wrap_before_declaration_rpar = false resharper_wrap_before_expression_rbrace = true resharper_wrap_before_extends_colon = false resharper_wrap_before_first_type_parameter_constraint = false resharper_wrap_before_invocation_lpar = false resharper_wrap_before_invocation_rpar = false resharper_wrap_before_linq_expression = false resharper_wrap_before_ternary_opsigns = true resharper_wrap_before_type_parameter_langle = false resharper_wrap_braced_init_list_style = wrap_if_long resharper_wrap_chained_binary_expressions = wrap_if_long resharper_wrap_chained_method_calls = wrap_if_long resharper_wrap_ctor_initializer_style = wrap_if_long resharper_wrap_enumeration_style = chop_if_long resharper_wrap_enum_declaration = chop_always resharper_wrap_extends_list_style = wrap_if_long resharper_wrap_for_stmt_header_style = chop_if_long resharper_wrap_multiple_declaration_style = chop_if_long resharper_wrap_multiple_type_parameter_constraints_style = chop_if_long resharper_wrap_object_and_collection_initializer_style = chop_if_long resharper_wrap_parameters_style = wrap_if_long resharper_wrap_property_pattern = chop_if_long resharper_wrap_switch_expression = chop_always resharper_wrap_ternary_expr_style = chop_if_long resharper_wrap_verbatim_interpolated_strings = no_wrap resharper_xmldoc_attribute_indent = single_indent resharper_xmldoc_linebreak_before_elements = summary,remarks,example,returns,param,typeparam,value,para resharper_xmldoc_max_blank_lines_between_tags = 0 resharper_xmldoc_max_line_length = 120 resharper_xmldoc_pi_attribute_style = do_not_touch resharper_xmldoc_space_before_self_closing = true resharper_xmldoc_wrap_lines = true resharper_xmldoc_wrap_tags_and_pi = true resharper_xmldoc_wrap_text = true resharper_xml_attribute_indent = align_by_first_attribute resharper_xml_linebreak_before_elements = resharper_xml_max_blank_lines_between_tags = 2 resharper_xml_max_line_length = 120 resharper_xml_pi_attribute_style = do_not_touch resharper_xml_space_before_self_closing = true resharper_xml_wrap_lines = true resharper_xml_wrap_tags_and_pi = true resharper_xml_wrap_text = false [*.asmdef] indent_style = space indent_size = 2 [*.{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}] indent_style = space indent_size = 4 tab_width = 4 ================================================ FILE: VirtueSky/Inspector/.github/ISSUE_TEMPLATE/bug_report.md ================================================ --- name: Bug report about: Create a report to help us improve title: '' labels: bug assignees: '' --- **Describe the bug** **Expected behavior** **Code Sample** ```csharp // ``` **Screenshots** **Desktop:** **Unity version:** **Tri Inspector version:** ================================================ FILE: VirtueSky/Inspector/.github/ISSUE_TEMPLATE/config.yml ================================================ blank_issues_enabled: false contact_links: - name: Feature request or Idea url: https://github.com/codewriter-packages/Tri-Inspector/discussions/categories/ideas about: Suggest an idea for this project. - name: Question url: https://github.com/codewriter-packages/Tri-Inspector/discussions/categories/q-a about: Please ask and answer questions here. ================================================ FILE: VirtueSky/Inspector/.github/release.yml ================================================ # .github/release.yml changelog: categories: - title: Breaking Changes labels: - breaking-change - title: Features labels: - enhancement - title: Fixes labels: - bug - title: Changes labels: - "*" ================================================ FILE: VirtueSky/Inspector/.gitignore ================================================ *.*~ *.db *.sln *.userprefs *.csproj *.pidb *.unityproj *.apk *.stackdump /Library /obj /Temp /Build* /Logs/ /AssetBundles /Logs/ .vs .vscode .idea .gradle *_LEGACY *.DotSettings.user /Assets/Plugins/Editor/JetBrains* /Assets/LEGACY* /Assets/TextMesh Pro* /Assets/Plugins/Sirenix* ================================================ FILE: VirtueSky/Inspector/Editor/AssemblyInfo.cs ================================================ using System.Runtime.CompilerServices; [assembly: InternalsVisibleTo("TriInspector.Editor.Extras")] [assembly: InternalsVisibleTo("TriInspector.Editor.Samples")] [assembly: InternalsVisibleTo("TriInspector.Editor.Integrations.Odin")] ================================================ FILE: VirtueSky/Inspector/Editor/AssemblyInfo.cs.meta ================================================ fileFormatVersion: 2 guid: 31eceb5f41944fc5a4afccb7697d3e61 timeCreated: 1652775741 ================================================ FILE: VirtueSky/Inspector/Editor/Attributes.cs ================================================ using System; namespace VirtueSky.Inspector { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] public class RegisterTriValueDrawerAttribute : Attribute { public RegisterTriValueDrawerAttribute(Type drawerType, int order) { DrawerType = drawerType; Order = order; } public Type DrawerType { get; } public int Order { get; } public bool ApplyOnArrayElement { get; set; } = true; } [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] public class RegisterTriAttributeDrawerAttribute : Attribute { public RegisterTriAttributeDrawerAttribute(Type drawerType, int order) { DrawerType = drawerType; Order = order; } public Type DrawerType { get; } public int Order { get; } public bool ApplyOnArrayElement { get; set; } } [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] public class RegisterTriGroupDrawerAttribute : Attribute { public RegisterTriGroupDrawerAttribute(Type drawerType) { DrawerType = drawerType; } public Type DrawerType { get; } } [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] public class RegisterTriPropertyHideProcessor : Attribute { public RegisterTriPropertyHideProcessor(Type processorType) { ProcessorType = processorType; } public Type ProcessorType { get; } public bool ApplyOnArrayElement { get; set; } } [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] public class RegisterTriPropertyDisableProcessor : Attribute { public RegisterTriPropertyDisableProcessor(Type processorType) { ProcessorType = processorType; } public Type ProcessorType { get; } public bool ApplyOnArrayElement { get; set; } } [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] public class RegisterTriValueValidatorAttribute : Attribute { public RegisterTriValueValidatorAttribute(Type validatorType) { ValidatorType = validatorType; } public Type ValidatorType { get; } public bool ApplyOnArrayElement { get; set; } = true; } [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] public class RegisterTriAttributeValidatorAttribute : Attribute { public RegisterTriAttributeValidatorAttribute(Type validatorType) { ValidatorType = validatorType; } public Type ValidatorType { get; } public bool ApplyOnArrayElement { get; set; } } [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] public class RegisterTriTypeProcessorAttribute : Attribute { public RegisterTriTypeProcessorAttribute(Type processorType, int order) { ProcessorType = processorType; Order = order; } public Type ProcessorType { get; } public int Order { get; } } } ================================================ FILE: VirtueSky/Inspector/Editor/Attributes.cs.meta ================================================ fileFormatVersion: 2 guid: 83289a1468a54453b62573925bc0635a timeCreated: 1639581370 ================================================ FILE: VirtueSky/Inspector/Editor/CustomizeDraw/EditorIconPostProcessor.cs ================================================ using System.Collections.Generic; using System.IO; using System.Linq; using UnityEditor; namespace VirtueSky.Inspector { /// /// 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. /// public class EditorIconPostProcessor : AssetPostprocessor { /// /// Called when new assets are imported, deleted or moved. /// /// Imported assets. /// Deleted assets. /// Moved assets. /// Moved from asset paths. static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths) { var metaChangedForAssets = new List(); foreach (string assetPath in importedAssets) { // NOTE: Below is not working since it's not compiled at this point // We therefore need to do some string manipulations... // var script = AssetDatabase.LoadAssetAtPath(assetPath); // var type = script?.GetClass(); var metaPath = $"{assetPath}.meta"; if (File.Exists(assetPath) && File.Exists(metaPath) && assetPath.EndsWith(".cs")) { // Hack, hack, hack away.... var scriptText = File.ReadAllText(assetPath); var containsEditorIconAttr = scriptText.Contains("[EditorIcon("); if (containsEditorIconAttr) { // Extract icon name from attribute // We are assuming that template strings are not used var attrIconNameStartIndex = scriptText.IndexOf("[EditorIcon(") + 13; var attrIconNameLength = scriptText.IndexOf("\")", attrIconNameStartIndex) - attrIconNameStartIndex; var iconName = scriptText.Substring(attrIconNameStartIndex, attrIconNameLength); // Find guid based on icon name from attr var iconGuids = AssetDatabase.FindAssets($"{iconName} t:texture2D"); var iconGuidsList = iconGuids.ToList(); var guid = iconGuidsList.FirstOrDefault(); if (!string.IsNullOrEmpty(guid)) { // Read meta for script var scriptMetaTextLines = File.ReadAllLines(metaPath); var metaIconLine = $"icon: {{fileID: 2800000, guid: {guid}, type: 3}}"; for (var i = 0; i < scriptMetaTextLines.Length; ++i) { var line = scriptMetaTextLines[i]; // Find icon line if (line.Contains("icon: ") && !line.Contains(metaIconLine)) { var indexIconKeyName = line.IndexOf("icon: "); var indexAfterClosingBrace = line.IndexOf("}", indexIconKeyName) + 1; var newLine = line.Replace( line.Substring(indexIconKeyName, indexAfterClosingBrace - indexIconKeyName), metaIconLine); scriptMetaTextLines[i] = newLine; File.WriteAllLines(metaPath, scriptMetaTextLines); metaChangedForAssets.Add(assetPath); break; } } } } } } // We need to reimport all assets where the meta was changed if (metaChangedForAssets.Count > 0) { foreach (var assetPath in metaChangedForAssets) { AssetDatabase.ImportAsset(assetPath); } } } } } ================================================ FILE: VirtueSky/Inspector/Editor/CustomizeDraw/EditorIconPostProcessor.cs.meta ================================================ fileFormatVersion: 2 guid: 01465eee3ed04ea2b30fe7e3ef9ae923 timeCreated: 1708661107 ================================================ FILE: VirtueSky/Inspector/Editor/CustomizeDraw/EnumAttribue/ExtendEnumDrawer.cs ================================================ using UnityEngine; using System.Collections.Generic; using System.IO; using UnityEditor; using System.Reflection; using System.Linq; namespace VirtueSky.Inspector { [CustomPropertyDrawer(typeof(ExtendEnumAttribute))] public class ExtendEnumDrawer : PropertyDrawer { //Some static values to pass back and forth with the popup static string newValueText = ""; static SerializedProperty currentProperty = null; static bool showWindow = false; static List enumNames; static int popupWidth = 150; static int popupHeight = 90; //Our class to make the popup public class NewValuePopup : PopupWindowContent { public override void OnGUI(Rect position) { EditorGUILayout.LabelField("New Value", EditorStyles.wordWrappedLabel); newValueText = GUILayout.TextField(newValueText).Trim(); float exitSize = 18; if (GUI.Button(new Rect(position.width - exitSize, 0, exitSize, exitSize), "X")) { this.editorWindow.Close(); } GUILayout.BeginHorizontal(); if (GUILayout.Button("Confirm")) { List names = enumNames; for (int i = 0; i < names.Count; i++) { names[i] = names[i].ToLower(); } if (!names.Contains(newValueText.ToLower())) { //This sends our enum to go get created. Be safe little enum. FindClassFile(GetEnumName(currentProperty), newValueText); this.editorWindow.Close(); } else { newValueText = newValueText + "_Copy"; } } if (GUILayout.Button("Cancel")) { this.editorWindow.Close(); } GUILayout.EndHorizontal(); GUIStyle small = new GUIStyle(EditorStyles.wordWrappedLabel); small.fontSize = 9; EditorGUILayout.LabelField("(To add multiple, separate with commas)", small); } public override void OnOpen() { showWindow = true; newValueText = ""; base.OnOpen(); } public override void OnClose() { showWindow = false; base.OnClose(); } public override Vector2 GetWindowSize() { return new Vector2(popupWidth, popupHeight); } } public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { currentProperty = property; ExtendEnumAttribute source = (ExtendEnumAttribute)attribute; System.Enum enumVal = GetBaseProperty(property); enumNames = (property.enumDisplayNames).OfType().ToList(); if (source.display) { int[] enumValues = (int[])(System.Enum.GetValues(enumVal.GetType())); for (int i = 0; i < enumNames.Count; i++) { enumNames[i] += " | " + enumValues[i]; } } EditorGUI.BeginProperty(position, label, property); if (!showWindow) { if (enumNames.Count != 0) { enumNames.Add("Add New..."); int newValue = EditorGUI.Popup(position, property.displayName, property.intValue, enumNames.ToArray()); if (newValue == enumNames.Count - 1) { NewValuePopup popup = new NewValuePopup(); PopupWindow.Show(new Rect(Screen.width / 2 - popupWidth / 2, position.y - popupHeight / 2, 0, 0), popup); newValueText = ""; } else { property.intValue = newValue; } } else { EditorGUI.LabelField(position, "Extendable Enums needs at least one value in your declared enum."); } } else { EditorGUI.LabelField(position, "Waiting for new value input."); } EditorGUI.EndProperty(); } //I know this is pretty much the same as GetBaseProperty, I was lazy, bite me. static string GetEnumName(SerializedProperty prop) { string[] separatedPaths = prop.propertyPath.Split('.'); System.Object reflectionTarget = prop.serializedObject.targetObject as object; foreach (var path in separatedPaths) { FieldInfo fieldInfo = reflectionTarget.GetType().GetField(path, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); string name = fieldInfo.FieldType.Name; return name; } return "Null"; } static T GetBaseProperty(SerializedProperty prop) { string[] separatedPaths = prop.propertyPath.Split('.'); System.Object reflectionTarget = prop.serializedObject.targetObject as object; foreach (var path in separatedPaths) { FieldInfo fieldInfo = reflectionTarget.GetType().GetField(path, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); reflectionTarget = fieldInfo.GetValue(reflectionTarget); } return (T)reflectionTarget; } static void FindClassFile(string enumName, string newEnum) { KeyValuePair codeFile = FindAllScriptFiles(Application.dataPath, "enum " + enumName); if (codeFile.Key != "NOPE") AddNewEnum(codeFile.Key, codeFile.Value, enumName, newEnum); else Debug.LogError("Could not find enum class"); } //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. //But it still works, so it's fine... for now. static void AddNewEnum(string classFile, string path, string enumName, string newEnum) { string[] originalSplit = classFile.Split(new[] { "enum " + enumName }, System.StringSplitOptions.RemoveEmptyEntries); string newHalf = originalSplit[1]; string enumSection = newHalf.Split('}')[0]; string[] commas = enumSection.Split(','); if (commas.Length == 0 && enumSection.Split('{')[0].Trim().Length == 0) //They've left the enum empty... for some reason. { Debug.Log("Uhh idk yet"); newHalf = newHalf.Replace(enumSection, enumSection + newEnum); } else { bool commaAfter = commas[commas.Length - 1].Trim().Length == 0; //This should check if the weirdo added a comma after their last enum value. if (commaAfter) { newHalf = newHalf.Replace(enumSection, enumSection + newEnum + ", "); } else { while (enumSection.Length > 0 && enumSection[enumSection.Length - 1] == ' ') enumSection = enumSection.Substring(0, enumSection.Length - 1); newHalf = newHalf.Replace(enumSection, enumSection + ", " + newEnum); } } string result = classFile.Replace(originalSplit[1], newHalf); using (var file = File.Open(path, FileMode.Create)) { using (var writer = new StreamWriter(file)) { writer.Write(result); } } AssetDatabase.Refresh(); } static KeyValuePair FindAllScriptFiles(string startDir, string enumToFind) { try { foreach (string file in Directory.GetFiles(startDir)) { if ((file.Contains(".cs") || file.Contains(".js")) && !file.Contains(".meta")) { string current = File.ReadAllText(file); string currentTrimmed = current.Replace(" ", "").Replace("\n", "").Replace("\t", "").Replace("\r", ""); if (currentTrimmed.Contains(enumToFind.Replace(" ", "") + "{")) return new KeyValuePair(current, file); } } foreach (string dir in Directory.GetDirectories(startDir)) { KeyValuePair result = FindAllScriptFiles(dir, enumToFind); if (result.Key != "NOPE") return result; } } catch (System.Exception ex) { Debug.Log(ex.Message); } return new KeyValuePair("NOPE", "NOPE"); } } } ================================================ FILE: VirtueSky/Inspector/Editor/CustomizeDraw/EnumAttribue/ExtendEnumDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: b07c545637af41f47a101b6cf470e89f timeCreated: 1521073357 licenseType: Store MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Inspector/Editor/CustomizeDraw/EnumAttribue/SearchableEnumDrawer.cs ================================================ using System; using UnityEditor; using UnityEngine; namespace VirtueSky.Inspector { /// /// Draws the custom enum selector popup for enum fileds using the /// SearchableEnumAttribute. /// [CustomPropertyDrawer(typeof(SearchableEnumAttribute))] public class SearchableEnumDrawer : PropertyDrawer { private const string TYPE_ERROR = "SearchableEnum can only be used on enum fields."; /// /// Cache of the hash to use to resolve the ID for the drawer. /// private int idHash; public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { // If this is not used on an eunum, show an error if (property.type != "Enum") { GUIStyle errorStyle = "CN EntryErrorIconSmall"; Rect r = new Rect(position); r.width = errorStyle.fixedWidth; position.xMin = r.xMax; GUI.Label(r, "", errorStyle); GUI.Label(position, TYPE_ERROR); return; } // By manually creating the control ID, we can keep the ID for the // label and button the same. This lets them be selected together // with the keyboard in the inspector, much like a normal popup. if (idHash == 0) idHash = "SearchableEnumDrawer".GetHashCode(); int id = GUIUtility.GetControlID(idHash, FocusType.Keyboard, position); label = EditorGUI.BeginProperty(position, label, property); position = EditorGUI.PrefixLabel(position, id, label); GUIContent buttonText; // If the enum has changed, a blank entry if (property.enumValueIndex < 0 || property.enumValueIndex >= property.enumDisplayNames.Length) { buttonText = new GUIContent(); } else { buttonText = new GUIContent(property.enumDisplayNames[property.enumValueIndex]); } if (DropdownButton(id, position, buttonText)) { Action onSelect = i => { property.enumValueIndex = i; property.serializedObject.ApplyModifiedProperties(); }; SearchablePopup.Show(position, property.enumDisplayNames, property.enumValueIndex, onSelect); } EditorGUI.EndProperty(); } /// /// A custom button drawer that allows for a controlID so that we can /// sync the button ID and the label ID to allow for keyboard /// navigation like the built-in enum drawers. /// private static bool DropdownButton(int id, Rect position, GUIContent content) { Event current = Event.current; switch (current.type) { case EventType.MouseDown: if (position.Contains(current.mousePosition) && current.button == 0) { Event.current.Use(); return true; } break; case EventType.KeyDown: if (GUIUtility.keyboardControl == id && current.character == '\n') { Event.current.Use(); return true; } break; case EventType.Repaint: EditorStyles.popup.Draw(position, content, id, false); break; } return false; } } } ================================================ FILE: VirtueSky/Inspector/Editor/CustomizeDraw/EnumAttribue/SearchableEnumDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: a8aa6bf08885446d813b3de2ed167fd6 timeCreated: 1700212255 ================================================ FILE: VirtueSky/Inspector/Editor/CustomizeDraw/EnumAttribue/SearchablePopup.cs ================================================ using System; using System.Collections.Generic; using UnityEditor; using UnityEngine; namespace VirtueSky.Inspector { /// /// A popup window that displays a list of options and may use a search /// string to filter the displayed content. /// public class SearchablePopup : PopupWindowContent { #region -- Constants -------------------------------------------------- /// Height of each element in the popup list. private const float ROW_HEIGHT = 16.0f; /// How far to indent list entries. private const float ROW_INDENT = 8.0f; /// Name to use for the text field for search. private const string SEARCH_CONTROL_NAME = "EnumSearchText"; #endregion -- Constants ----------------------------------------------- #region -- Static Functions ------------------------------------------- /// Show a new SearchablePopup. /// /// Rectangle of the button that triggered the popup. /// /// List of strings to choose from. /// /// Index of the currently selected string. /// /// /// Callback to trigger when a choice is made. /// public static void Show(Rect activatorRect, string[] options, int current, Action onSelectionMade) { SearchablePopup win = new SearchablePopup(options, current, onSelectionMade); PopupWindow.Show(activatorRect, win); } /// /// Force the focused window to redraw. This can be used to make the /// popup more responsive to mouse movement. /// private static void Repaint() { EditorWindow.focusedWindow.Repaint(); } /// Draw a generic box. /// Where to draw. /// Color to tint the box. private static void DrawBox(Rect rect, Color tint) { Color c = GUI.color; GUI.color = tint; GUI.Box(rect, "", Selection); GUI.color = c; } #endregion -- Static Functions ---------------------------------------- #region -- Helper Classes --------------------------------------------- /// /// Stores a list of strings and can return a subset of that list that /// matches a given filter string. /// private class FilteredList { /// /// An entry in the filtererd list, mapping the text to the /// original index. /// public struct Entry { public int Index; public string Text; } /// All posibile items in the list. private readonly string[] allItems; /// Create a new filtered list. /// All The items to filter. public FilteredList(string[] items) { allItems = items; Entries = new List(); UpdateFilter(""); } /// The current string filtering the list. public string Filter { get; private set; } /// All valid entries for the current filter. public List Entries { get; private set; } /// Total possible entries in the list. public int MaxLength { get { return allItems.Length; } } /// /// Sets a new filter string and updates the Entries that match the /// new filter if it has changed. /// /// String to use to filter the list. /// /// True if the filter is updated, false if newFilter is the same /// as the current Filter and no update is necessary. /// public bool UpdateFilter(string filter) { if (Filter == filter) return false; Filter = filter; Entries.Clear(); for (int i = 0; i < allItems.Length; i++) { if (string.IsNullOrEmpty(Filter) || allItems[i].ToLower().Contains(Filter.ToLower())) { Entry entry = new Entry { Index = i, Text = allItems[i] }; if (string.Equals(allItems[i], Filter, StringComparison.CurrentCultureIgnoreCase)) Entries.Insert(0, entry); else Entries.Add(entry); } } return true; } } #endregion -- Helper Classes ------------------------------------------ #region -- Private Variables ------------------------------------------ /// Callback to trigger when an item is selected. private readonly Action onSelectionMade; /// /// Index of the item that was selected when the list was opened. /// private readonly int currentIndex; /// /// Container for all available options that does the actual string /// filtering of the content. /// private readonly FilteredList list; /// Scroll offset for the vertical scroll area. private Vector2 scroll; /// /// Index of the item under the mouse or selected with the keyboard. /// private int hoverIndex; /// /// An item index to scroll to on the next draw. /// private int scrollToIndex; /// /// An offset to apply after scrolling to scrollToIndex. This can be /// used to control if the selection appears at the top, bottom, or /// center of the popup. /// private float scrollOffset; #endregion -- Private Variables --------------------------------------- #region -- GUI Styles ------------------------------------------------- // GUIStyles implicitly cast from a string. This triggers a lookup into // the current skin which will be the editor skin and lets us get some // built-in styles. private static GUIStyle SearchBox = "ToolbarSeachTextField"; private static GUIStyle CancelButton = "ToolbarSeachCancelButton"; private static GUIStyle DisabledCancelButton = "ToolbarSeachCancelButtonEmpty"; private static GUIStyle Selection = "SelectionRect"; #endregion -- GUI Styles ---------------------------------------------- #region -- Initialization --------------------------------------------- private SearchablePopup(string[] names, int currentIndex, Action onSelectionMade) { list = new FilteredList(names); this.currentIndex = currentIndex; this.onSelectionMade = onSelectionMade; hoverIndex = currentIndex; scrollToIndex = currentIndex; scrollOffset = GetWindowSize().y - ROW_HEIGHT * 2; } #endregion -- Initialization ------------------------------------------ #region -- PopupWindowContent Overrides ------------------------------- public override void OnOpen() { base.OnOpen(); // Force a repaint every frame to be responsive to mouse hover. EditorApplication.update += Repaint; } public override void OnClose() { base.OnClose(); EditorApplication.update -= Repaint; } public override Vector2 GetWindowSize() { return new Vector2(base.GetWindowSize().x, Mathf.Min(600, list.MaxLength * ROW_HEIGHT + EditorStyles.toolbar.fixedHeight)); } public override void OnGUI(Rect rect) { Rect searchRect = new Rect(0, 0, rect.width, EditorStyles.toolbar.fixedHeight); Rect scrollRect = Rect.MinMaxRect(0, searchRect.yMax, rect.xMax, rect.yMax); HandleKeyboard(); DrawSearch(searchRect); DrawSelectionArea(scrollRect); } #endregion -- PopupWindowContent Overrides ---------------------------- #region -- GUI -------------------------------------------------------- private void DrawSearch(Rect rect) { if (Event.current.type == EventType.Repaint) EditorStyles.toolbar.Draw(rect, false, false, false, false); Rect searchRect = new Rect(rect); searchRect.xMin += 6; searchRect.xMax -= 6; searchRect.y += 2; searchRect.width -= CancelButton.fixedWidth; GUI.FocusControl(SEARCH_CONTROL_NAME); GUI.SetNextControlName(SEARCH_CONTROL_NAME); string newText = GUI.TextField(searchRect, list.Filter, SearchBox); if (list.UpdateFilter(newText)) { hoverIndex = 0; scroll = Vector2.zero; } searchRect.x = searchRect.xMax; searchRect.width = CancelButton.fixedWidth; if (string.IsNullOrEmpty(list.Filter)) GUI.Box(searchRect, GUIContent.none, DisabledCancelButton); else if (GUI.Button(searchRect, "x", CancelButton)) { list.UpdateFilter(""); scroll = Vector2.zero; } } private void DrawSelectionArea(Rect scrollRect) { Rect contentRect = new Rect(0, 0, scrollRect.width - GUI.skin.verticalScrollbar.fixedWidth, list.Entries.Count * ROW_HEIGHT); scroll = GUI.BeginScrollView(scrollRect, scroll, contentRect); Rect rowRect = new Rect(0, 0, scrollRect.width, ROW_HEIGHT); for (int i = 0; i < list.Entries.Count; i++) { if (scrollToIndex == i && (Event.current.type == EventType.Repaint || Event.current.type == EventType.Layout)) { Rect r = new Rect(rowRect); r.y += scrollOffset; GUI.ScrollTo(r); scrollToIndex = -1; scroll.x = 0; } if (rowRect.Contains(Event.current.mousePosition)) { if (Event.current.type == EventType.MouseMove || Event.current.type == EventType.ScrollWheel) hoverIndex = i; if (Event.current.type == EventType.MouseDown) { onSelectionMade(list.Entries[i].Index); EditorWindow.focusedWindow.Close(); } } DrawRow(rowRect, i); rowRect.y = rowRect.yMax; } GUI.EndScrollView(); } private void DrawRow(Rect rowRect, int i) { if (list.Entries[i].Index == currentIndex) DrawBox(rowRect, Color.cyan); else if (i == hoverIndex) DrawBox(rowRect, Color.white); Rect labelRect = new Rect(rowRect); labelRect.xMin += ROW_INDENT; GUI.Label(labelRect, list.Entries[i].Text); } /// /// Process keyboard input to navigate the choices or make a selection. /// private void HandleKeyboard() { if (Event.current.type == EventType.KeyDown) { if (Event.current.keyCode == KeyCode.DownArrow) { hoverIndex = Mathf.Min(list.Entries.Count - 1, hoverIndex + 1); Event.current.Use(); scrollToIndex = hoverIndex; scrollOffset = ROW_HEIGHT; } if (Event.current.keyCode == KeyCode.UpArrow) { hoverIndex = Mathf.Max(0, hoverIndex - 1); Event.current.Use(); scrollToIndex = hoverIndex; scrollOffset = -ROW_HEIGHT; } if (Event.current.keyCode == KeyCode.Return) { if (hoverIndex >= 0 && hoverIndex < list.Entries.Count) { onSelectionMade(list.Entries[hoverIndex].Index); EditorWindow.focusedWindow.Close(); } } if (Event.current.keyCode == KeyCode.Escape) { EditorWindow.focusedWindow.Close(); } } } #endregion -- GUI ----------------------------------------------------- } } ================================================ FILE: VirtueSky/Inspector/Editor/CustomizeDraw/EnumAttribue/SearchablePopup.cs.meta ================================================ fileFormatVersion: 2 guid: c47838d170794dbfa710dc4df2fe039e timeCreated: 1700212328 ================================================ FILE: VirtueSky/Inspector/Editor/CustomizeDraw/EnumAttribue.meta ================================================ fileFormatVersion: 2 guid: 7b63b2018c2b4135a61979cfe3964c52 timeCreated: 1700212559 ================================================ FILE: VirtueSky/Inspector/Editor/CustomizeDraw/HeaderLineDrawer.cs ================================================ using UnityEditor; using UnityEngine; using VirtueSky.Utils; namespace VirtueSky.Inspector { [CustomPropertyDrawer(typeof(HeaderLineAttribute))] public class HeaderLineDrawer : DecoratorDrawer { private HeaderLineAttribute Target => attribute as HeaderLineAttribute; private GUIStyle m_style = new GUIStyle(EditorStyles.boldLabel); protected float singleLine = EditorGUIUtility.singleLineHeight; public override void OnGUI(Rect _rect) { //Draw label if (!string.IsNullOrWhiteSpace(Target.text)) { EditorGUI.LabelField(_rect, Target.isToUpper ? Target.text.ToUpper() : Target.text, m_style); //Move to new line and set following line height _rect.y += singleLine + 1; _rect.height = 1; } else { _rect.y += singleLine / 2f + 1; _rect.height = 1; } m_style.normal.textColor = Target.colorText.ToColor(); // Color c = Target.colorText.ToColor(); // if (EditorGUIUtility.isProSkin) // { // c = m_style.normal.textColor; // } //Draw spacer UtilityDraw.CreateLineSpacer(EditorGUI.IndentedRect(_rect), Target.colorLine.ToColor(), _rect.height); } //How tall the GUI is for this decorator public override float GetHeight() { return singleLine * 1.25f; } } } ================================================ FILE: VirtueSky/Inspector/Editor/CustomizeDraw/HeaderLineDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: e244a49e59664803b3397f5d84655d94 timeCreated: 1700193347 ================================================ FILE: VirtueSky/Inspector/Editor/CustomizeDraw/HelpDrawer.cs ================================================ using UnityEditor; using UnityEngine; namespace VirtueSky.Inspector { #if UNITY_EDITOR [CustomPropertyDrawer(typeof(HelpBoxAttribute))] public class HelpDrawer : PropertyDrawer { // Used for top and bottom padding between the text and the HelpBox border. const int paddingHeight = 8; // Used to add some margin between the the HelpBox and the property. const int marginHeight = 2; // Global field to store the original (base) property height. float baseHeight = 0; // Custom added height for drawing text area which has the MultilineAttribute. float addedHeight = 0; /// /// A wrapper which returns the PropertyDrawer.attribute field as a HelpAttribute. /// HelpBoxAttribute HelpBoxAttribute { get { return (HelpBoxAttribute)attribute; } } /// /// A helper property to check for RangeAttribute. /// RangeAttribute rangeAttribute { get { var attributes = fieldInfo.GetCustomAttributes(typeof(RangeAttribute), true); return attributes != null && attributes.Length > 0 ? (RangeAttribute)attributes[0] : null; } } /// /// A helper property to check for MultiLineAttribute. /// MultilineAttribute multilineAttribute { get { var attributes = fieldInfo.GetCustomAttributes(typeof(MultilineAttribute), true); return attributes != null && attributes.Length > 0 ? (MultilineAttribute)attributes[0] : null; } } public override float GetPropertyHeight(SerializedProperty prop, GUIContent label) { // We store the original property height for later use... baseHeight = base.GetPropertyHeight(prop, label); // This stops icon shrinking if text content doesn't fill out the container enough. float minHeight = paddingHeight * 5; // Calculate the height of the HelpBox using the GUIStyle on the current skin and the inspector // window's currentViewWidth. var content = new GUIContent(HelpBoxAttribute.text); var style = GUI.skin.GetStyle("helpbox"); var height = style.CalcHeight(content, EditorGUIUtility.currentViewWidth); // We add tiny padding here to make sure the text is not overflowing the HelpBox from the top // and bottom. height += marginHeight * 2; // Since we draw a custom text area with the label above if our property contains the // MultilineAttribute, we need to add some extra height to compensate. This is stored in a // seperate global field so we can use it again later. if (multilineAttribute != null && prop.propertyType == SerializedPropertyType.String) { addedHeight = 48f; } // If the calculated HelpBox is less than our minimum height we use this to calculate the returned // height instead. return height > minHeight ? height + baseHeight + addedHeight : minHeight + baseHeight + addedHeight; } public override void OnGUI(Rect position, SerializedProperty prop, GUIContent label) { // We get a local reference to the MultilineAttribute as we use it twice in this method and it // saves calling the logic twice for minimal optimization, etc... var multiline = multilineAttribute; EditorGUI.BeginProperty(position, label, prop); // Copy the position out so we can calculate the position of our HelpBox without affecting the // original position. var helpPos = position; helpPos.height -= baseHeight + marginHeight; if (multiline != null) { helpPos.height -= addedHeight; } // Renders the HelpBox in the Unity inspector UI. EditorGUI.HelpBox(helpPos, HelpBoxAttribute.text, HelpBoxAttribute.type); position.y += helpPos.height + marginHeight; position.height = baseHeight; // If we have a RangeAttribute on our field, we need to handle the PropertyDrawer differently to // keep the same style as Unity's default. var range = rangeAttribute; if (range != null) { if (prop.propertyType == SerializedPropertyType.Float) { EditorGUI.Slider(position, prop, range.min, range.max, label); } else if (prop.propertyType == SerializedPropertyType.Integer) { EditorGUI.IntSlider(position, prop, (int)range.min, (int)range.max, label); } else { // Not numeric so draw standard property field as punishment for adding RangeAttribute to // a property which can not have a range :P EditorGUI.PropertyField(position, prop, label); } } else if (multiline != null) { // Here's where we handle the PropertyDrawer differently if we have a MultiLineAttribute, to try // and keep some kind of multiline text area. This is not identical to Unity's default but is // better than nothing... if (prop.propertyType == SerializedPropertyType.String) { var style = GUI.skin.label; var size = style.CalcHeight(label, EditorGUIUtility.currentViewWidth); EditorGUI.LabelField(position, label); position.y += size; position.height += addedHeight - size; // Fixed text dissappearing thanks to: http://answers.unity3d.com/questions/244043/textarea-does-not-work-text-dissapears-solution-is.html prop.stringValue = EditorGUI.TextArea(position, prop.stringValue); } else { // Again with a MultilineAttribute on a non-text field deserves for the standard property field // to be drawn as punishment :P EditorGUI.PropertyField(position, prop, label); } } else { // If we get to here it means we're drawing the default property field below the HelpBox. More custom // and built in PropertyDrawers could be implemented to enable HelpBox but it could easily make for // hefty else/if block which would need refactoring! EditorGUI.PropertyField(position, prop, label); } EditorGUI.EndProperty(); } } #else // Replicate MessageType Enum if we are not in editor as this enum exists in UnityEditor namespace. // This should stop errors being logged the same as Shawn Featherly's commit in the Github repo but I // feel is cleaner than having the conditional directive in the middle of the HelpAttribute constructor. public enum MessageType { None, Info, Warning, Error, } #endif } ================================================ FILE: VirtueSky/Inspector/Editor/CustomizeDraw/HelpDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: 184ad84ff1994cd9acb68ceb52fa5af8 timeCreated: 1700132045 ================================================ FILE: VirtueSky/Inspector/Editor/CustomizeDraw/HighlightDrawer.cs ================================================ using System; using System.Linq; using UnityEngine; using UnityEditor; using System.Reflection; using VirtueSky.Utils; namespace VirtueSky.Inspector { [CustomPropertyDrawer(typeof(HighlightAttribute))] public class HighlightDrawer : PropertyDrawer { public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { var highlightAttribute = attribute as HighlightAttribute; bool doHighlight = true; if (!string.IsNullOrEmpty(highlightAttribute.validateField)) { var t = property.serializedObject.targetObject.GetType(); var methodInfo = t.GetMethod(highlightAttribute.validateField, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); var fieldInfo = t.GetField(highlightAttribute.validateField, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); var propertyInfo = t.GetProperty(highlightAttribute.validateField, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); if (methodInfo != null) { doHighlight = (bool)methodInfo.Invoke(property.serializedObject.targetObject, null) == (bool)highlightAttribute.comparationValue; ; } // else // { // Debug.LogError("Invalid Validate function: " + highlightAttribute.ValidateField, property.serializedObject.targetObject); // } if (fieldInfo != null) { SerializedProperty conditionField = property.serializedObject.FindProperty(highlightAttribute.validateField); // We check that exist a Field with the parameter name if (conditionField == null) { //ShowError(position, label, "Error getting the condition Field. Check the name."); return; } switch (conditionField.propertyType) { case SerializedPropertyType.Boolean: try { bool comparationValue = highlightAttribute.comparationValue == null || (bool)highlightAttribute.comparationValue; doHighlight = conditionField.boolValue == comparationValue; } catch { // ShowError(position, label, "Invalid comparation Value Type"); return; } break; case SerializedPropertyType.Enum: object paramEnum = highlightAttribute.comparationValue; object[] paramEnumArray = highlightAttribute.comparationValueArray; if (paramEnum == null && paramEnumArray == null) { doHighlight = true; // ShowError(position, label, "The comparation enum value is null"); return; } else if (UtilityDraw.IsEnum(paramEnum)) { if (!UtilityDraw.CheckSameEnumType(new[] { paramEnum.GetType() }, property.serializedObject.targetObject.GetType(), conditionField.propertyPath)) { doHighlight = true; //ShowError(position, label, "Enum Types doesn't match"); return; } else { string enumValue = Enum.GetValues(paramEnum.GetType()).GetValue(conditionField.enumValueIndex).ToString(); if (paramEnum.ToString() != enumValue) doHighlight = false; else doHighlight = true; } } else if (UtilityDraw.IsEnum(paramEnumArray)) { if (!UtilityDraw.CheckSameEnumType(paramEnumArray.Select(x => x.GetType()), property.serializedObject.targetObject.GetType(), conditionField.propertyPath)) { doHighlight = true; //ShowError(position, label, "Enum Types doesn't match"); return; } else { string enumValue = Enum.GetValues(paramEnumArray[0].GetType()).GetValue(conditionField.enumValueIndex).ToString(); if (paramEnumArray.All(x => x.ToString() != enumValue)) doHighlight = false; else doHighlight = true; } } else { doHighlight = true; // ShowError(position, label, "The comparation enum value is not an enum"); return; } break; case SerializedPropertyType.Integer: case SerializedPropertyType.Float: string stringValue; bool error = false; float conditionValue = 0; if (conditionField.propertyType == SerializedPropertyType.Integer) conditionValue = conditionField.intValue; else if (conditionField.propertyType == SerializedPropertyType.Float) conditionValue = conditionField.floatValue; try { stringValue = (string)highlightAttribute.comparationValue; } catch { doHighlight = true; //ShowError(position, label, "Invalid comparation Value Type"); return; } if (stringValue.StartsWith("==")) { float? value = UtilityDraw.GetValue(stringValue, "=="); if (value == null) error = true; else doHighlight = conditionValue == value; } else if (stringValue.StartsWith("!=")) { float? value = UtilityDraw.GetValue(stringValue, "!="); if (value == null) error = true; else doHighlight = conditionValue != value; } else if (stringValue.StartsWith("<=")) { float? value = UtilityDraw.GetValue(stringValue, "<="); if (value == null) error = true; else doHighlight = conditionValue <= value; } else if (stringValue.StartsWith(">=")) { float? value = UtilityDraw.GetValue(stringValue, ">="); if (value == null) error = true; else doHighlight = conditionValue >= value; } else if (stringValue.StartsWith("<")) { float? value = UtilityDraw.GetValue(stringValue, "<"); if (value == null) error = true; else doHighlight = conditionValue < value; } else if (stringValue.StartsWith(">")) { float? value = UtilityDraw.GetValue(stringValue, ">"); if (value == null) error = true; else doHighlight = conditionValue > value; } if (error) { doHighlight = true; // ShowError(position, label, "Invalid comparation instruction for Int or float value"); return; } break; default: doHighlight = true; // ShowError(position, label, "This type has not supported."); return; } } else if (propertyInfo != null) { doHighlight = (bool)propertyInfo.GetValue(property.serializedObject.targetObject) == (bool)highlightAttribute.comparationValue; } } if (doHighlight) { // get the highlight color var color = ColorExtensions.ToColor(highlightAttribute.highColor); // create a ractangle to draw the highlight to, slightly larger than our property var padding = EditorGUIUtility.standardVerticalSpacing; var highlightRect = new Rect(position.x - padding, position.y - padding, position.width + (padding * 2), position.height + (padding * 2)); // draw the highlight first EditorGUI.DrawRect(highlightRect, color); // make sure the propertys text is dark and easy to read over the bright highlight var cc = GUI.contentColor; GUI.contentColor = Color.black; // draw the property ontop of the highlight EditorGUI.PropertyField(position, property, label); GUI.contentColor = cc; } else { EditorGUI.PropertyField(position, property, label); } } public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { return EditorGUI.GetPropertyHeight(property, label, true); } } } ================================================ FILE: VirtueSky/Inspector/Editor/CustomizeDraw/HighlightDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: 038a4bb11bb84e6da267561eb762ba04 timeCreated: 1700214706 ================================================ FILE: VirtueSky/Inspector/Editor/CustomizeDraw/LayerAttributeDraw.cs ================================================ using UnityEditor; using UnityEngine; namespace VirtueSky.Inspector { [CustomPropertyDrawer(typeof(LayerAttribute))] public class LayerAttributeDraw : PropertyDrawer { public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { if (property.propertyType != SerializedPropertyType.Integer) { //Debug.LogWarning("Layer attribute must be used with 'int' property type"); //base.OnGUI(position, property, label); EditorGUI.LabelField(position, "Layer attribute must be used with 'int' property type", new GUIStyle { normal = new GUIStyleState { textColor = Color.yellow } }); return; } property.intValue = EditorGUI.LayerField(position, label, property.intValue); } } } ================================================ FILE: VirtueSky/Inspector/Editor/CustomizeDraw/LayerAttributeDraw.cs.meta ================================================ fileFormatVersion: 2 guid: ae0951f67191478d99efd3b92319f6a3 timeCreated: 1700035279 ================================================ FILE: VirtueSky/Inspector/Editor/CustomizeDraw/TagAttributeDraw.cs ================================================ using UnityEditor; using UnityEngine; namespace VirtueSky.Inspector { [CustomPropertyDrawer(typeof(TagAttribute))] public class TagAttributeDraw : PropertyDrawer { public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { if (property.propertyType != SerializedPropertyType.String) { //Debug.LogWarning("Tag attribute must be used with 'string' property type"); //base.OnGUI(position, property, label); EditorGUI.LabelField(position, "Tag attribute must be used with 'string' property type", new GUIStyle { normal = new GUIStyleState { textColor = Color.yellow } }); return; } if (property.stringValue == "") { property.stringValue = UnityEditorInternal.InternalEditorUtility.tags[0]; } property.stringValue = EditorGUI.TagField(position, label, property.stringValue); } } } ================================================ FILE: VirtueSky/Inspector/Editor/CustomizeDraw/TagAttributeDraw.cs.meta ================================================ fileFormatVersion: 2 guid: 13463e988ddc4f80a546b417f0c2f3b6 timeCreated: 1700034947 ================================================ FILE: VirtueSky/Inspector/Editor/CustomizeDraw/TitleColorAttributeDrawer.cs ================================================ using UnityEditor; using UnityEngine; using VirtueSky.Utils; namespace VirtueSky.Inspector { [CustomPropertyDrawer(typeof(TitleColorAttribute))] public class TitleColorAttributeDrawer : DecoratorDrawer { private float _nestedMinimumXPosition = 18f; private float _paddingRightLine = 10f; public override float GetHeight() { TitleColorAttribute titleColorAttribute = (TitleColorAttribute)attribute; return titleColorAttribute.Spacing + titleColorAttribute.LineHeight + titleColorAttribute.Spacing; } public override void OnGUI(Rect position) { Rect rect = EditorGUI.IndentedRect(position); rect.y += EditorGUIUtility.singleLineHeight / 2f; TitleColorAttribute titleColorAttribute = (TitleColorAttribute)attribute; Color lineColor = titleColorAttribute.LineColor.ToColor(); if (string.IsNullOrEmpty(titleColorAttribute.Title)) { rect.height = titleColorAttribute.LineHeight; EditorGUI.DrawRect(rect, lineColor); return; } // Label style GUIStyle style = new GUIStyle(EditorStyles.label) { richText = true }; style.stretchWidth = true; style.clipping = TextClipping.Overflow; GUIContent label = new GUIContent($"{titleColorAttribute.Title}"); Vector2 textSize = style.CalcSize(label); float linesRectWidth = (position.width - textSize.x) / 2f; float labelPaddingSize = 5f; if (titleColorAttribute.AlignTitleLeft) { var rigthLinePositionX = position.xMin + textSize.x + labelPaddingSize + _paddingRightLine; Rect labelLeftRect = new Rect(position.xMin, position.yMin - (titleColorAttribute.Spacing * 0.01f), textSize.x, position.height); if (rect.xMin > _nestedMinimumXPosition) { rigthLinePositionX = labelLeftRect.xMax + labelPaddingSize * 2 + (rect.xMin / 2f); } Rect RightRect = new Rect(rigthLinePositionX, position.yMin + titleColorAttribute.Spacing, position.width - textSize.x - 10f, titleColorAttribute.LineHeight); EditorGUI.LabelField(labelLeftRect, label, style); EditorGUI.DrawRect(RightRect, lineColor); return; } Rect leftLineRect = new Rect(position.xMin, position.yMin + titleColorAttribute.Spacing, linesRectWidth, titleColorAttribute.LineHeight); var labelPositionX = leftLineRect.xMax + labelPaddingSize; var rightLineRectWidth = linesRectWidth - _paddingRightLine; // If the rect is nested inside a list or an object's property if (rect.xMin > _nestedMinimumXPosition) { labelPositionX = leftLineRect.xMax - (rect.xMin / 2f); rightLineRectWidth = linesRectWidth; } Rect labelRect = new Rect(labelPositionX, position.yMin - (titleColorAttribute.Spacing * 0.01f), textSize.x, position.height); var rightLinePositionX = rect.xMin > _nestedMinimumXPosition ? labelRect.xMax + labelPaddingSize * 2 + (rect.xMin / 2f) : labelRect.xMax + labelPaddingSize; Rect rightLineRect = new Rect(rightLinePositionX, position.yMin + titleColorAttribute.Spacing, rightLineRectWidth, titleColorAttribute.LineHeight); EditorGUI.DrawRect(leftLineRect, lineColor); EditorGUI.LabelField(labelRect, label, style); EditorGUI.DrawRect(rightLineRect, lineColor); } } } ================================================ FILE: VirtueSky/Inspector/Editor/CustomizeDraw/TitleColorAttributeDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: 7592c31d65ed40bb84faca2bbdaf3104 timeCreated: 1700209364 ================================================ FILE: VirtueSky/Inspector/Editor/CustomizeDraw/UtilityDraw.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using UnityEditor; using UnityEngine; namespace VirtueSky.Inspector { public static class UtilityDraw { /// /// Return if the object is enum and not null /// public static bool IsEnum(object obj) { return obj != null && obj.GetType().IsEnum; } /// /// Return if all the objects are enums and not null /// public static bool IsEnum(object[] obj) { return obj != null && obj.All(o => o.GetType().IsEnum); } /// /// Check if the field with name "fieldName" has the same class as the "checkTypes" classes through reflection /// public static bool CheckSameEnumType(IEnumerable checkTypes, Type classType, string fieldName) { string[] fieldNames = fieldName.Split('.'); Type currentType = classType; foreach (var name in fieldNames) { FieldInfo field = currentType.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); PropertyInfo property = currentType.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { currentType = field.FieldType; } else if (property != null) { currentType = property.PropertyType; } else { return false; } } return checkTypes.All(x => x == currentType); } /// /// Return the float value in the content string removing the remove string /// public static float? GetValue(string content, string remove) { string removed = content.Replace(remove, ""); try { return float.Parse(removed); } catch { return null; } } public static void CreateLineSpacer(Rect _rect, Color _color, float _height = 2) { _rect.height = _height; Color oldColour = GUI.color; GUI.color = _color; EditorGUI.DrawRect(_rect, _color); GUI.color = oldColour; } } } ================================================ FILE: VirtueSky/Inspector/Editor/CustomizeDraw/UtilityDraw.cs.meta ================================================ fileFormatVersion: 2 guid: 90c43d5003974388a0c80118cb2e7170 timeCreated: 1700161538 ================================================ FILE: VirtueSky/Inspector/Editor/CustomizeDraw.meta ================================================ fileFormatVersion: 2 guid: 6bc1040c970fb164bb6fc07f5f9d0bf8 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Inspector/Editor/Editors/TriEditor.cs ================================================ using UnityEditor; using UnityEngine.UIElements; namespace VirtueSky.Inspector.Editors { public abstract class TriEditor : Editor { private TriEditorCore _core; protected virtual void OnEnable() { _core = new TriEditorCore(this); } protected virtual void OnDisable() { _core.Dispose(); } public override void OnInspectorGUI() { _core.OnInspectorGUI(); } public override VisualElement CreateInspectorGUI() { return _core.CreateVisualElement(); } } } ================================================ FILE: VirtueSky/Inspector/Editor/Editors/TriEditor.cs.meta ================================================ fileFormatVersion: 2 guid: 7985f723508b7434183568ca5c8436bd MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Inspector/Editor/Editors/TriEditorCore.cs ================================================ using System.Collections.Generic; using VirtueSky.Inspector; using VirtueSky.Inspector.Utilities; using UnityEditor; using UnityEngine; using UnityEngine.UIElements; namespace VirtueSky.Inspector.Editors { public class TriEditorCore { public static readonly Dictionary UiElementsRoots = new Dictionary(); private readonly Editor _editor; private TriPropertyTreeForSerializedObject _inspector; public TriEditorCore(Editor editor) { _editor = editor; } public void Dispose() { if (_inspector != null) { UiElementsRoots.Remove(_inspector); _inspector.Dispose(); } _inspector = null; } public void OnInspectorGUI(VisualElement visualRoot = null) { var serializedObject = _editor.serializedObject; if (serializedObject.targetObjects.Length == 0) { return; } if (serializedObject.targetObject == null) { EditorGUILayout.HelpBox("Script is missing", MessageType.Warning); return; } foreach (var targetObject in serializedObject.targetObjects) { if (TriGuiHelper.IsEditorTargetPushed(targetObject)) { GUILayout.Label("Recursive inline editors not supported"); return; } } if (_inspector == null) { _inspector = new TriPropertyTreeForSerializedObject(serializedObject); } if (visualRoot != null) { UiElementsRoots[_inspector] = visualRoot; } serializedObject.UpdateIfRequiredOrScript(); _inspector.Update(); _inspector.RunValidationIfRequired(); EditorGUIUtility.hierarchyMode = false; using (TriGuiHelper.PushEditorTarget(serializedObject.targetObject)) { _inspector.Draw(); } if (serializedObject.ApplyModifiedProperties()) { _inspector.RequestValidation(); } if (_inspector.RepaintRequired) { _editor.Repaint(); } } public VisualElement CreateVisualElement() { var container = new VisualElement(); var root = new VisualElement() { style = { position = Position.Absolute, }, }; container.Add(new IMGUIContainer(() => { const float labelExtraPadding = 2; const float labelWidthRatio = 0.45f; const float labelMinWidth = 120; var space = container.resolvedStyle.left + container.resolvedStyle.right + labelExtraPadding; EditorGUIUtility.wideMode = true; EditorGUIUtility.hierarchyMode = false; EditorGUIUtility.labelWidth = Mathf.Max(labelMinWidth, container.resolvedStyle.width * labelWidthRatio - space); GUILayout.BeginVertical(Styles.RootLayout); OnInspectorGUI(root); GUILayout.EndVertical(); }) { style = { marginLeft = -Styles.RootMarginLeft, marginRight = -Styles.RootMarginRight, }, }); container.Add(root); return container; } private static class Styles { public const int RootMarginLeft = 15; public const int RootMarginRight = 6; public static readonly GUIStyle RootLayout = new GUIStyle { padding = new RectOffset(RootMarginLeft, RootMarginRight, 0, 0), }; } } } ================================================ FILE: VirtueSky/Inspector/Editor/Editors/TriEditorCore.cs.meta ================================================ fileFormatVersion: 2 guid: a7bd33877ecd42dc878e2b28f0a9f581 timeCreated: 1694856077 ================================================ FILE: VirtueSky/Inspector/Editor/Editors/TriMonoBehaviourEditor.cs ================================================ using UnityEditor; using UnityEngine; namespace VirtueSky.Inspector.Editors { [CanEditMultipleObjects] [CustomEditor(typeof(MonoBehaviour), editorForChildClasses: true, isFallback = true)] internal sealed class TriMonoBehaviourEditor : TriEditor { } } ================================================ FILE: VirtueSky/Inspector/Editor/Editors/TriMonoBehaviourEditor.cs.meta ================================================ fileFormatVersion: 2 guid: ebc893dd0ca44a789a00c03f7a71dc56 timeCreated: 1683784191 ================================================ FILE: VirtueSky/Inspector/Editor/Editors/TriScriptableObjectEditor.cs ================================================ using UnityEditor; using UnityEngine; namespace VirtueSky.Inspector.Editors { [CanEditMultipleObjects] [CustomEditor(typeof(ScriptableObject), editorForChildClasses: true, isFallback = true)] internal sealed class TriScriptableObjectEditor : TriEditor { } } ================================================ FILE: VirtueSky/Inspector/Editor/Editors/TriScriptableObjectEditor.cs.meta ================================================ fileFormatVersion: 2 guid: 5fe6a72a9e734fcc8ab5f29cd13c9d53 timeCreated: 1683784197 ================================================ FILE: VirtueSky/Inspector/Editor/Editors/TriScriptedImporterEditor.cs ================================================ using VirtueSky.InspectorUnityInternalBridge; using UnityEditor; using UnityEngine.UIElements; #if UNITY_2020_2_OR_NEWER using UnityEditor.AssetImporters; #else using UnityEditor.Experimental.AssetImporters; #endif namespace VirtueSky.Inspector.Editors { [CanEditMultipleObjects] [CustomEditor(typeof(ScriptedImporter), editorForChildClasses: true)] public sealed class TriScriptedImporterEditor : ScriptedImporterEditor { private TriEditorCore _core; public override void OnEnable() { base.OnEnable(); _core = new TriEditorCore(this); } public override void OnDisable() { _core.Dispose(); base.OnDisable(); } public override void OnInspectorGUI() { _core.OnInspectorGUI(); ApplyRevertGUI(); } public override VisualElement CreateInspectorGUI() { var root = new VisualElement(); root.Add(_core.CreateVisualElement()); root.Add(new IMGUIContainer(() => DoImporterDefaultGUI())); return root; } private void DoImporterDefaultGUI() { if (extraDataType != null) { EditorProxy.DoDrawDefaultInspector(extraDataSerializedObject); } ApplyRevertGUI(); } } } ================================================ FILE: VirtueSky/Inspector/Editor/Editors/TriScriptedImporterEditor.cs.meta ================================================ fileFormatVersion: 2 guid: 421d7c27350d45308b6a91b76560bb50 timeCreated: 1683784201 ================================================ FILE: VirtueSky/Inspector/Editor/Editors/TriSettingsProvider.cs ================================================ using UnityEditor; namespace VirtueSky.Inspector.Editors { public class TriSettingsProvider : SettingsProvider { private class Styles { } public TriSettingsProvider() : base("Project/Tri Inspector", SettingsScope.Project) { } public override void OnGUI(string searchContext) { EditorGUI.BeginDisabledGroup(EditorApplication.isCompiling); base.OnGUI(searchContext); EditorGUI.EndDisabledGroup(); } [SettingsProvider] public static SettingsProvider CreateTriInspectorSettingsProvider() { var provider = new TriSettingsProvider { keywords = GetSearchKeywordsFromGUIContentProperties(), }; return provider; } } } ================================================ FILE: VirtueSky/Inspector/Editor/Editors/TriSettingsProvider.cs.meta ================================================ fileFormatVersion: 2 guid: e21ace13982a498283f60e3271c86551 timeCreated: 1651644353 ================================================ FILE: VirtueSky/Inspector/Editor/Editors.meta ================================================ fileFormatVersion: 2 guid: d685f31e94904c5d9319405aa8b775f9 timeCreated: 1638856449 ================================================ FILE: VirtueSky/Inspector/Editor/Elements/InlineEditorElement.cs ================================================ using VirtueSky.InspectorUnityInternalBridge; using UnityEditor; using UnityEngine; namespace VirtueSky.Inspector.Elements { public class InlineEditorElement : TriElement { private readonly TriProperty _property; private readonly Props _props; private Editor _editor; private Rect _editorPosition; private bool _dirty; [System.Serializable] public struct Props { public InlineEditorModes mode; public float previewHeight; public bool DrawGUI => (mode & InlineEditorModes.GUIOnly) != 0; public bool DrawHeader => (mode & InlineEditorModes.Header) != 0; public bool DrawPreview => (mode & InlineEditorModes.Preview) != 0; } public InlineEditorElement(TriProperty property, Props props = default) { _property = property; _props = props; _editorPosition = Rect.zero; } protected override void OnDetachFromPanel() { if (_editor != null) { Object.DestroyImmediate(_editor); } base.OnDetachFromPanel(); } public override bool Update() { if (_editor == null || _editor.target != (Object) _property.Value) { if (_editor != null) { Object.DestroyImmediate(_editor); } _dirty = true; } if (_dirty) { _dirty = false; return true; } return false; } public override float GetHeight(float width) { if (_property.IsExpanded && !_property.IsValueMixed) { return _editorPosition.height; } return 0f; } public override void OnGUI(Rect position) { if (Event.current.type == EventType.Repaint) { _editorPosition = position; } var lastEditorRect = Rect.zero; var shouldDrawEditor = _property.IsExpanded && !_property.IsValueMixed; if (_editor == null && shouldDrawEditor && _property.Value is Object obj && obj != null) { _editor = Editor.CreateEditor(obj); if (!InternalEditorUtilityProxy.GetIsInspectorExpanded(obj)) { InternalEditorUtilityProxy.SetIsInspectorExpanded(obj, true); } } if (_editor != null && shouldDrawEditor) { GUILayout.BeginArea(_editorPosition); GUILayout.BeginVertical(); if (_props.DrawHeader || _props.DrawGUI) { GUILayout.BeginVertical(); if (_props.DrawHeader) { GUILayout.BeginVertical(); _editor.DrawHeader(); GUILayout.EndVertical(); } if (_props.DrawGUI) { GUILayout.BeginVertical(); _editor.OnInspectorGUI(); GUILayout.EndVertical(); } GUILayout.EndVertical(); } if (_props.DrawPreview && _editor.HasPreviewGUI()) { GUILayout.BeginVertical(); var previewOpts = new[] {GUILayout.ExpandWidth(true), GUILayout.Height(_props.previewHeight),}; var previewRect = EditorGUILayout.GetControlRect(false, _props.previewHeight, previewOpts); previewRect.width = Mathf.Max(previewRect.width, 10); previewRect.height = Mathf.Max(previewRect.height, 10); var guiEnabled = GUI.enabled; GUI.enabled = true; _editor.DrawPreview(previewRect); GUI.enabled = guiEnabled; GUILayout.EndVertical(); } GUILayout.EndVertical(); lastEditorRect = GUILayoutUtility.GetLastRect(); GUILayout.EndArea(); } else { if (_editor != null) { Object.DestroyImmediate(_editor); } } if (Event.current.type == EventType.Repaint && !Mathf.Approximately(_editorPosition.height, lastEditorRect.height)) { _editorPosition.height = lastEditorRect.height; _dirty = true; _property.PropertyTree.RequestRepaint(); } } } } ================================================ FILE: VirtueSky/Inspector/Editor/Elements/InlineEditorElement.cs.meta ================================================ fileFormatVersion: 2 guid: e5abb7004e824b6d87bae69c80c8df1d timeCreated: 1641802293 ================================================ FILE: VirtueSky/Inspector/Editor/Elements/TriBoxGroupElement.cs ================================================ using System; using JetBrains.Annotations; using VirtueSky.Inspector.Resolvers; using VirtueSky.Inspector.Utilities; using UnityEditor; using UnityEngine; namespace VirtueSky.Inspector.Elements { public class TriBoxGroupElement : TriHeaderGroupBaseElement { private readonly Props _props; private ValueResolver _headerResolver; [CanBeNull] private TriProperty _firstProperty; [CanBeNull] private TriProperty _toggleProperty; private bool _expanded; [Serializable] public new struct Props { public string title; public TitleMode titleMode; public bool expandedByDefault; public bool hideIfChildrenInvisible; } public TriBoxGroupElement(Props props = default) : base(new TriHeaderGroupBaseElement.Props { hideIfChildrenInvisible = props.hideIfChildrenInvisible, }) { _props = props; _expanded = _props.expandedByDefault; } protected override void AddPropertyChild(TriElement element, TriProperty property) { _firstProperty = property; _headerResolver = ValueResolver.ResolveString(property.Definition, _props.title ?? ""); if (_headerResolver.TryGetErrorString(out var error)) { AddChild(new TriInfoBoxElement(error, TriMessageType.Error)); } if (_props.titleMode == TitleMode.Toggle) { if (_toggleProperty == null) { if (property.ValueType == typeof(bool)) { _toggleProperty = property; return; } if (property.ChildrenProperties?.Count > 0) { var childrenProperty = property.ChildrenProperties[0]; if (childrenProperty.ValueType == typeof(bool)) { _toggleProperty = childrenProperty; } } } } base.AddPropertyChild(element, property); } protected override float GetHeaderHeight(float width) { if (_props.titleMode == TitleMode.Hidden) { return 0f; } return base.GetHeaderHeight(width); } protected override float GetContentHeight(float width) { if (((_props.titleMode == TitleMode.Toggle && _props.expandedByDefault) || _props.titleMode == TitleMode.Foldout) && !_expanded) { return 0f; } return base.GetContentHeight(width); } protected override void DrawHeader(Rect position) { TriEditorGUI.DrawBox(position, TriEditorStyles.TabOnlyOne); var headerLabelRect = new Rect(position) { xMin = position.xMin + 6, xMax = position.xMax - 6, yMin = position.yMin + 2, yMax = position.yMax - 2, }; var headerContent = _headerResolver.GetValue(_firstProperty); switch (_props.titleMode) { case TitleMode.Foldout: _expanded = EditorGUI.Foldout(headerLabelRect, _expanded, headerContent, true); break; case TitleMode.Toggle: { if (_toggleProperty?.Value is bool cachedValue) { var newValue = EditorGUI.ToggleLeft(headerLabelRect, headerContent, cachedValue); if (newValue != cachedValue) { _toggleProperty.SetValue(newValue); } _expanded = newValue; } else { EditorGUI.LabelField(headerLabelRect, $"The first property in the group must be of bool."); } break; } default: EditorGUI.LabelField(headerLabelRect, headerContent); break; } } protected override void DrawContent(Rect position) { if (_props.titleMode == TitleMode.Foldout && !_expanded) { return; } if (_props.titleMode == TitleMode.Toggle && !_props.expandedByDefault && !_expanded) { EditorGUI.BeginDisabledGroup(true); base.DrawContent(position); EditorGUI.EndDisabledGroup(); return; } base.DrawContent(position); } public enum TitleMode { Normal, Hidden, Foldout, Toggle, } } } ================================================ FILE: VirtueSky/Inspector/Editor/Elements/TriBoxGroupElement.cs.meta ================================================ fileFormatVersion: 2 guid: c7a787b7a5e844a2a12192a9d52984b0 timeCreated: 1641802243 ================================================ FILE: VirtueSky/Inspector/Editor/Elements/TriBuiltInPropertyElement.cs ================================================ using VirtueSky.InspectorUnityInternalBridge; using UnityEditor; using UnityEngine; namespace VirtueSky.Inspector.Elements { public class TriBuiltInPropertyElement : TriElement { private readonly TriProperty _property; private readonly PropertyHandlerProxy _propertyHandler; private readonly SerializedProperty _serializedProperty; public TriBuiltInPropertyElement( TriProperty property, SerializedProperty serializedProperty, PropertyHandlerProxy propertyHandler) { _property = property; _serializedProperty = serializedProperty; _propertyHandler = propertyHandler; } public override float GetHeight(float width) { return _propertyHandler.GetHeight(_serializedProperty, _property.DisplayNameContent, true); } public override void OnGUI(Rect position) { EditorGUI.BeginChangeCheck(); if (_property.IsArrayElement && _serializedProperty.propertyType == SerializedPropertyType.Generic && _serializedProperty.hasVisibleChildren) { position.xMin += 12; } _propertyHandler.OnGUI(position, _serializedProperty, _property.DisplayNameContent, true); if (EditorGUI.EndChangeCheck()) { _property.NotifyValueChanged(); } } } } ================================================ FILE: VirtueSky/Inspector/Editor/Elements/TriBuiltInPropertyElement.cs.meta ================================================ fileFormatVersion: 2 guid: cb76597978d84d19a27f6e8596e1a4bf timeCreated: 1638774260 ================================================ FILE: VirtueSky/Inspector/Editor/Elements/TriDropdownElement.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using UnityEditor; using UnityEngine; namespace VirtueSky.Inspector.Elements { public class TriDropdownElement : TriElement { private readonly TriProperty _property; private readonly Func> _valuesGetter; private object _currentValue; private string _currentText; private bool _hasNextValue; private object _nextValue; public TriDropdownElement(TriProperty property, Func> valuesGetter) { _property = property; _valuesGetter = valuesGetter; } public override float GetHeight(float width) { return EditorGUIUtility.singleLineHeight; } public override void OnGUI(Rect position) { if (_hasNextValue) { var nextValue = _nextValue; _hasNextValue = false; _nextValue = null; _property.SetValue(nextValue); GUI.changed = true; } if (!_property.Comparer.Equals(_currentValue, _property.Value)) { _currentValue = _property.Value; _currentText = _valuesGetter.Invoke(_property) .FirstOrDefault(it => _property.Comparer.Equals(it.Value, _property.Value)) ?.Text ?? (_property.Value?.ToString() ?? string.Empty); } var controlId = GUIUtility.GetControlID(FocusType.Passive); position = EditorGUI.PrefixLabel(position, controlId, _property.DisplayNameContent); if (GUI.Button(position, _currentText, EditorStyles.popup)) { ShowDropdown(position); } } private void ShowDropdown(Rect position) { var items = _valuesGetter.Invoke(_property); var menu = new GenericMenu(); foreach (var item in items) { var isOn = _property.Comparer.Equals(item.Value, _property.Value); menu.AddItem(new GUIContent(item.Text), isOn, ChangeValue, item.Value); } menu.DropDown(position); void ChangeValue(object v) { _nextValue = v; _hasNextValue = true; _property.PropertyTree.RequestRepaint(); } } } } ================================================ FILE: VirtueSky/Inspector/Editor/Elements/TriDropdownElement.cs.meta ================================================ fileFormatVersion: 2 guid: 0bfe47c1836e47c48920fb74982c89cb timeCreated: 1657812638 ================================================ FILE: VirtueSky/Inspector/Editor/Elements/TriFoldoutElement.cs ================================================ using VirtueSky.Inspector.Utilities; using UnityEditor; using UnityEngine; namespace VirtueSky.Inspector.Elements { internal class TriFoldoutElement : TriPropertyCollectionBaseElement { private readonly TriProperty _property; public TriFoldoutElement(TriProperty property) { _property = property; DeclareGroups(property.ValueType); } public override bool Update() { var dirty = false; if (_property.IsExpanded) { dirty |= GenerateChildren(); } else { dirty |= ClearChildren(); } dirty |= base.Update(); return dirty; } public override float GetHeight(float width) { var height = EditorGUIUtility.singleLineHeight; if (!_property.IsExpanded) { return height; } height += base.GetHeight(width); return height; } public override void OnGUI(Rect position) { var headerRect = new Rect(position) { height = EditorGUIUtility.singleLineHeight, }; var contentRect = new Rect(position) { yMin = position.yMin + headerRect.height, }; TriEditorGUI.Foldout(headerRect, _property); if (!_property.IsExpanded) { return; } using (var indentedRectScope = TriGuiHelper.PushIndentedRect(contentRect, 1)) { base.OnGUI(indentedRectScope.IndentedRect); } } private bool GenerateChildren() { if (ChildrenCount != 0) { return false; } foreach (var childProperty in _property.ChildrenProperties) { AddProperty(childProperty); } return true; } private bool ClearChildren() { if (ChildrenCount == 0) { return false; } RemoveAllChildren(); return true; } } } ================================================ FILE: VirtueSky/Inspector/Editor/Elements/TriFoldoutElement.cs.meta ================================================ fileFormatVersion: 2 guid: 90b64b1805694cf8999a0380d4ca70b6 timeCreated: 1638772042 ================================================ FILE: VirtueSky/Inspector/Editor/Elements/TriHeaderGroupBaseElement.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using VirtueSky.Inspector.Utilities; using UnityEditor; using UnityEngine; namespace VirtueSky.Inspector.Elements { public abstract class TriHeaderGroupBaseElement : TriPropertyCollectionBaseElement { private readonly Props _props; private const float InsetTop = 4; private const float InsetBottom = 4; private const float InsetLeft = 4; private const float InsetRight = 4; private readonly List _properties = new List(); private bool IsAnyPropertyVisible => _properties.Any(it => it.IsVisible); [Serializable] public struct Props { public bool hideIfChildrenInvisible; } protected TriHeaderGroupBaseElement(Props props = default) { _props = props; } protected override void AddPropertyChild(TriElement element, TriProperty property) { _properties.Add(property); base.AddPropertyChild(element, property); } protected virtual float GetHeaderHeight(float width) { return 22; } protected virtual float GetContentHeight(float width) { return base.GetHeight(width); } protected virtual void DrawHeader(Rect position) { } protected virtual void DrawContent(Rect position) { base.OnGUI(position); } public sealed override float GetHeight(float width) { if (_props.hideIfChildrenInvisible && !IsAnyPropertyVisible) { return -EditorGUIUtility.standardVerticalSpacing; } var headerHeight = GetHeaderHeight(width); var contentHeight = GetContentHeight(width); var height = headerHeight + contentHeight; if (contentHeight > 0) { height += InsetTop + InsetBottom; } return height; } public sealed override void OnGUI(Rect position) { if (_props.hideIfChildrenInvisible && !IsAnyPropertyVisible) { return; } var headerHeight = GetHeaderHeight(position.width); var contentHeight = GetContentHeight(position.width); var headerBgRect = new Rect(position) { height = headerHeight, }; var contentBgRect = new Rect(position) { yMin = headerBgRect.yMax, }; var contentRect = new Rect(contentBgRect) { xMin = contentBgRect.xMin + InsetLeft, xMax = contentBgRect.xMax - InsetRight, yMin = contentBgRect.yMin + InsetTop, yMax = contentBgRect.yMax - InsetBottom, height = contentHeight, }; if (headerHeight > 0f) { DrawHeader(headerBgRect); } if (contentHeight > 0) { TriEditorGUI.DrawBox(contentBgRect, headerHeight > 0f ? TriEditorStyles.ContentBox : TriEditorStyles.Box); using (TriGuiHelper.PushLabelWidth(EditorGUIUtility.labelWidth - InsetLeft)) { DrawContent(contentRect); } } } } } ================================================ FILE: VirtueSky/Inspector/Editor/Elements/TriHeaderGroupBaseElement.cs.meta ================================================ fileFormatVersion: 2 guid: 7406688f5ef349a3ae0acee7ea9ec935 timeCreated: 1642760804 ================================================ FILE: VirtueSky/Inspector/Editor/Elements/TriHorizontalGroupElement.cs ================================================ using System; using VirtueSky.Inspector.Utilities; using UnityEditor; using UnityEngine; namespace VirtueSky.Inspector.Elements { public class TriHorizontalGroupElement : TriPropertyCollectionBaseElement { private readonly float[] _sizes; private readonly float _totalFixedSize; public TriHorizontalGroupElement(float[] sizes = null) { _sizes = sizes ?? Array.Empty(); _totalFixedSize = 0f; for (var index = 0; index < _sizes.Length; index++) { if (TryGetFixedSizeByIndex(index, out var fixedSize)) { _totalFixedSize += fixedSize; } } } public override float GetHeight(float width) { if (ChildrenCount == 0) { return 0f; } var spacing = EditorGUIUtility.standardVerticalSpacing; var totalSpacing = spacing * (ChildrenCount - 1); var totalDynamic = width - totalSpacing - _totalFixedSize; var dynamicChildCount = GetDynamicChildCount(); var height = 0f; for (var i = 0; i < ChildrenCount; i++) { var childWidth = GetChildWidth(i, totalDynamic, dynamicChildCount); var child = GetChild(i); var childHeight = child.GetHeight(childWidth); height = Mathf.Max(height, childHeight); } return height; } public override void OnGUI(Rect position) { if (ChildrenCount == 0) { return; } var spacing = EditorGUIUtility.standardVerticalSpacing; var totalSpacing = spacing * (ChildrenCount - 1); var totalDynamic = position.width - totalSpacing - _totalFixedSize; var dynamicChildCount = GetDynamicChildCount(); var xOffset = 0f; for (var i = 0; i < ChildrenCount; i++) { var childWidth = GetChildWidth(i, totalDynamic, dynamicChildCount); var child = GetChild(i); var childRect = new Rect(position) { width = childWidth, height = child.GetHeight(childWidth), x = position.xMin + xOffset, }; using (TriGuiHelper.PushLabelWidth(EditorGUIUtility.labelWidth / ChildrenCount)) { child.OnGUI(childRect); } xOffset += childWidth + spacing; } } private float GetDynamicChildCount() { var count = 0f; for (var i = 0; i < ChildrenCount; i++) { if (TryGetFixedSizeByIndex(i, out _)) { continue; } count++; } return count; } private float GetChildWidth(int i, float totalDynamic, float dynamicChildCount) { if (TryGetFixedSizeByIndex(i, out var fixedSize)) { return fixedSize; } return totalDynamic / dynamicChildCount; } private bool TryGetFixedSizeByIndex(int index, out float fixedSize) { if (index < _sizes.Length && _sizes[index] > 0f) { fixedSize = _sizes[index]; return true; } fixedSize = 0f; return false; } } } ================================================ FILE: VirtueSky/Inspector/Editor/Elements/TriHorizontalGroupElement.cs.meta ================================================ fileFormatVersion: 2 guid: e609cf56a7e242d8b9cb5813178a7e69 timeCreated: 1642259149 ================================================ FILE: VirtueSky/Inspector/Editor/Elements/TriInfoBoxElement.cs ================================================ using System; using VirtueSky.Inspector.Utilities; using VirtueSky.InspectorUnityInternalBridge; using UnityEditor; using UnityEngine; namespace VirtueSky.Inspector.Elements { public class TriInfoBoxElement : TriElement { private const int ActionSpacing = 5; private const int ActionWidth = 100; private const int ActionWidthWithSpacing = ActionWidth + ActionSpacing * 2; private readonly GUIContent _message; private readonly Texture2D _icon; private readonly Color _color; private readonly Action _inlineAction; private readonly GUIContent _inlineActionContent; public TriInfoBoxElement(string message, TriMessageType type = TriMessageType.None, Color? color = null, Action inlineAction = null, GUIContent inlineActionContent = null) { var messageType = GetMessageType(type); _icon = EditorGUIUtilityProxy.GetHelpIcon(messageType); _message = new GUIContent(message); _color = color ?? GetColor(type); _inlineAction = inlineAction; _inlineActionContent = inlineActionContent ?? GUIContent.none; } public override float GetHeight(float width) { var labelWidth = width; if (_inlineAction != null) { labelWidth -= ActionWidthWithSpacing; } var style = _icon == null ? Styles.InfoBoxContentNone : Styles.InfoBoxContent; var height = style.CalcHeight(_message, labelWidth); if (_inlineAction != null) { height = Mathf.Max(height, CalcActionHeight() + ActionSpacing * 2); } return Mathf.Max(26, height); } public override void OnGUI(Rect position) { using (TriGuiHelper.PushColor(_color)) { GUI.Label(position, string.Empty, Styles.InfoBoxBg); } var labelWidth = position.width; if (_inlineAction != null) { labelWidth -= ActionWidthWithSpacing; } if (_icon != null) { var labelRect = new Rect(position) { width = labelWidth, }; var iconRect = new Rect(position) { xMin = position.xMin + 4, width = 20, }; GUI.Label(labelRect, _message, Styles.InfoBoxContent); GUI.DrawTexture(iconRect, _icon, ScaleMode.ScaleToFit); } else { GUI.Label(position, _message, Styles.InfoBoxContentNone); } if (_inlineAction != null) { var fixHeight = CalcActionHeight(); var actionRect = new Rect(position) { xMax = position.xMax - ActionSpacing, xMin = position.xMax - ActionWidth - ActionSpacing, yMin = position.center.y - fixHeight / 2, yMax = position.center.y + fixHeight / 2, }; if (GUI.Button(actionRect, _inlineActionContent, Styles.InfoBoxInlineAction)) { _inlineAction?.Invoke(); } } } private float CalcActionHeight() { return Styles.InfoBoxInlineAction.CalcHeight(_inlineActionContent, ActionWidth); } private static Color GetColor(TriMessageType type) { switch (type) { case TriMessageType.Error: return new Color(1f, 0.4f, 0.4f); case TriMessageType.Warning: return new Color(1f, 0.8f, 0.2f); default: return Color.white; } } private static MessageType GetMessageType(TriMessageType type) { switch (type) { case TriMessageType.None: return MessageType.None; case TriMessageType.Info: return MessageType.Info; case TriMessageType.Warning: return MessageType.Warning; case TriMessageType.Error: return MessageType.Error; default: return MessageType.None; } } private static class Styles { public static readonly GUIStyle InfoBoxBg; public static readonly GUIStyle InfoBoxContent; public static readonly GUIStyle InfoBoxContentNone; public static readonly GUIStyle InfoBoxInlineAction; static Styles() { InfoBoxBg = new GUIStyle(EditorStyles.helpBox); InfoBoxContentNone = new GUIStyle(EditorStyles.label) { padding = new RectOffset(4, 4, 4, 4), fontSize = InfoBoxBg.fontSize, alignment = TextAnchor.MiddleLeft, wordWrap = true, }; InfoBoxContent = new GUIStyle(InfoBoxContentNone) { padding = new RectOffset(26, 4, 4, 4), }; InfoBoxInlineAction = new GUIStyle(GUI.skin.button) { wordWrap = true, }; } } } } ================================================ FILE: VirtueSky/Inspector/Editor/Elements/TriInfoBoxElement.cs.meta ================================================ fileFormatVersion: 2 guid: f64a66d501c34a808686c834530dd9a9 timeCreated: 1638860979 ================================================ FILE: VirtueSky/Inspector/Editor/Elements/TriInlineGenericElement.cs ================================================ using System; using VirtueSky.Inspector.Utilities; using UnityEditor; using UnityEngine; namespace VirtueSky.Inspector.Elements { internal class TriInlineGenericElement : TriPropertyCollectionBaseElement { private readonly Props _props; private readonly TriProperty _property; [Serializable] public struct Props { public bool drawPrefixLabel; public float labelWidth; } public TriInlineGenericElement(TriProperty property, Props props = default) { _property = property; _props = props; DeclareGroups(property.ValueType); foreach (var childProperty in property.ChildrenProperties) { AddProperty(childProperty); } } public override void OnGUI(Rect position) { if (_props.drawPrefixLabel) { var controlId = GUIUtility.GetControlID(FocusType.Passive); position = EditorGUI.PrefixLabel(position, controlId, _property.DisplayNameContent); } using (TriGuiHelper.PushLabelWidth(_props.labelWidth)) { base.OnGUI(position); } } } } ================================================ FILE: VirtueSky/Inspector/Editor/Elements/TriInlineGenericElement.cs.meta ================================================ fileFormatVersion: 2 guid: a5124d0a8d93488a858723d80fe69e69 timeCreated: 1638788657 ================================================ FILE: VirtueSky/Inspector/Editor/Elements/TriLabelElement.cs ================================================ using UnityEngine; namespace VirtueSky.Inspector.Elements { public class TriLabelElement : TriElement { private readonly GUIContent _label; public TriLabelElement(string label, string tooltip = "") { _label = new GUIContent(label, tooltip); } public TriLabelElement(GUIContent label) { _label = label; } public override float GetHeight(float width) { return GUI.skin.label.CalcHeight(_label, width); } public override void OnGUI(Rect position) { GUI.Label(position, _label); } } } ================================================ FILE: VirtueSky/Inspector/Editor/Elements/TriLabelElement.cs.meta ================================================ fileFormatVersion: 2 guid: a193f4236257483a8d5a10f0025b3d4f timeCreated: 1638771650 ================================================ FILE: VirtueSky/Inspector/Editor/Elements/TriListElement.cs ================================================ using System; using System.Collections; using System.Linq; using VirtueSky.InspectorUnityInternalBridge; using VirtueSky.Inspector.Utilities; using UnityEditor; using UnityEditorInternal; using UnityEngine; using Object = UnityEngine.Object; namespace VirtueSky.Inspector.Elements { public class TriListElement : TriElement { private const int MinElementsForVirtualization = 25; private const float ListExtraWidth = 7f; private const float DraggableAreaExtraWidth = 14f; private readonly TriProperty _property; private readonly ReorderableList _reorderableListGui; private readonly bool _alwaysExpanded; private readonly bool _showElementLabels; private readonly bool _showAlternatingBackground; private float _lastContentWidth; private int? _lastInvisibleElement; private int? _lastVisibleElement; protected ReorderableList ListGui => _reorderableListGui; public TriListElement(TriProperty property) { property.TryGetAttribute(out ListDrawerSettingsAttribute settings); _property = property; _alwaysExpanded = settings?.AlwaysExpanded ?? false; _showElementLabels = settings?.ShowElementLabels ?? false; _showAlternatingBackground = settings?.ShowAlternatingBackground ?? true; _reorderableListGui = new ReorderableList(null, _property.ArrayElementType) { showDefaultBackground = settings?.ShowDefaultBackground ?? true, draggable = settings?.Draggable ?? true, displayAdd = settings == null || !settings.HideAddButton, displayRemove = settings == null || !settings.HideRemoveButton, drawHeaderCallback = DrawHeaderCallback, elementHeightCallback = ElementHeightCallback, drawElementBackgroundCallback = DrawElementBackgroundCallback, drawElementCallback = DrawElementCallback, onAddCallback = AddElementCallback, onRemoveCallback = RemoveElementCallback, onReorderCallbackWithDetails = ReorderCallback, }; if (!_reorderableListGui.displayAdd && !_reorderableListGui.displayRemove) { _reorderableListGui.footerHeight = 0f; } } public override bool Update() { var dirty = false; if (_property.TryGetSerializedProperty(out var serializedProperty) && serializedProperty.isArray) { _reorderableListGui.serializedProperty = serializedProperty; } else if (_property.Value != null) { _reorderableListGui.list = (IList) _property.Value; } else if (_reorderableListGui.list == null) { _reorderableListGui.list = (IList) (_property.FieldType.IsArray ? Array.CreateInstance(_property.ArrayElementType, 0) : Activator.CreateInstance(_property.FieldType)); } if (_alwaysExpanded && !_property.IsExpanded) { _property.IsExpanded = true; } if (_property.IsExpanded) { dirty |= GenerateChildren(); } else { dirty |= ClearChildren(); } dirty |= base.Update(); if (dirty) { ReorderableListProxy.ClearCacheRecursive(_reorderableListGui); } return dirty; } public override float GetHeight(float width) { if (!_property.IsExpanded) { return _reorderableListGui.headerHeight + 4f; } _lastContentWidth = width; return _reorderableListGui.GetHeight(); } public override void OnGUI(Rect position) { if (!_property.IsExpanded) { _lastInvisibleElement = null; _lastVisibleElement = null; ReorderableListProxy.DoListHeader(_reorderableListGui, new Rect(position) { yMax = position.yMax - 4, }); return; } if (_reorderableListGui.count < MinElementsForVirtualization) { _lastInvisibleElement = null; _lastVisibleElement = null; } var labelWidthExtra = ListExtraWidth + DraggableAreaExtraWidth; using (TriGuiHelper.PushLabelWidth(EditorGUIUtility.labelWidth - labelWidthExtra)) { _reorderableListGui.DoList(position); } } private void AddElementCallback(ReorderableList reorderableList) { AddElementCallback(reorderableList, null); } private void AddElementCallback(ReorderableList reorderableList, Object addedReferenceValue) { if (_property.TryGetSerializedProperty(out _)) { ReorderableListProxy.DoAddButton(reorderableList, addedReferenceValue); _property.NotifyValueChanged(); return; } var template = CloneValue(_property); _property.SetValues(targetIndex => { var value = (IList) _property.GetValue(targetIndex); if (_property.FieldType.IsArray) { var array = Array.CreateInstance(_property.ArrayElementType, template.Length + 1); Array.Copy(template, array, template.Length); if (addedReferenceValue != null) { array.SetValue(addedReferenceValue, array.Length - 1); } value = array; } else { if (value == null) { value = (IList) Activator.CreateInstance(_property.FieldType); } var newElement = addedReferenceValue != null ? addedReferenceValue : CreateDefaultElementValue(_property); value.Add(newElement); } return value; }); } private void RemoveElementCallback(ReorderableList reorderableList) { if (_property.TryGetSerializedProperty(out _)) { ReorderableListProxy.defaultBehaviours.DoRemoveButton(reorderableList); _property.NotifyValueChanged(); return; } var template = CloneValue(_property); var ind = reorderableList.index; _property.SetValues(targetIndex => { var value = (IList) _property.GetValue(targetIndex); if (_property.FieldType.IsArray) { var array = Array.CreateInstance(_property.ArrayElementType, template.Length - 1); Array.Copy(template, 0, array, 0, ind); Array.Copy(template, ind + 1, array, ind, array.Length - ind); value = array; } else { value?.RemoveAt(ind); } return value; }); } private void ReorderCallback(ReorderableList list, int oldIndex, int newIndex) { if (_property.TryGetSerializedProperty(out _)) { _property.NotifyValueChanged(); return; } var mainValue = _property.Value; _property.SetValues(targetIndex => { var value = (IList) _property.GetValue(targetIndex); if (value == mainValue) { return value; } var element = value[oldIndex]; for (var index = 0; index < value.Count - 1; ++index) { if (index >= oldIndex) { value[index] = value[index + 1]; } } for (var index = value.Count - 1; index > 0; --index) { if (index > newIndex) { value[index] = value[index - 1]; } } value[newIndex] = element; return value; }); } private void SetArraySizeCallback(int arraySize) { if (arraySize < 0) { return; } if (_property.TryGetSerializedProperty(out var serializedProperty)) { serializedProperty.arraySize = arraySize; _property.NotifyValueChanged(); return; } var template = CloneValue(_property); _property.SetValues(targetIndex => { var value = (IList) _property.GetValue(targetIndex); if (_property.FieldType.IsArray) { var array = Array.CreateInstance(_property.ArrayElementType, arraySize); Array.Copy(template, array, Math.Min(arraySize, template.Length)); value = array; } else { if (value == null) { value = (IList) Activator.CreateInstance(_property.FieldType); } while (value.Count > arraySize) { value.RemoveAt(value.Count - 1); } while (value.Count < arraySize) { var newElement = CreateDefaultElementValue(_property); value.Add(newElement); } } return value; }); } private bool GenerateChildren() { var count = _reorderableListGui.count; if (ChildrenCount == count) { return false; } while (ChildrenCount < count) { var property = _property.ArrayElementProperties[ChildrenCount]; AddChild(CreateItemElement(property)); } while (ChildrenCount > count) { RemoveChildAt(ChildrenCount - 1); } return true; } private bool ClearChildren() { if (ChildrenCount == 0) { return false; } RemoveAllChildren(); return true; } protected virtual TriElement CreateItemElement(TriProperty property) { return new TriPropertyElement(property, new TriPropertyElement.Props { forceInline = !_showElementLabels, }); } private void DrawHeaderCallback(Rect rect) { var labelRect = new Rect(rect) { xMax = rect.xMax - 50, }; var arraySizeRect = new Rect(rect) { xMin = labelRect.xMax, }; if (_alwaysExpanded) { EditorGUI.LabelField(labelRect, _property.DisplayNameContent); } else { TriEditorGUI.Foldout(labelRect, _property); } EditorGUI.BeginChangeCheck(); var newArraySize = EditorGUI.DelayedIntField(arraySizeRect, _reorderableListGui.count); if (EditorGUI.EndChangeCheck()) { SetArraySizeCallback(newArraySize); return; } if (Event.current.type == EventType.DragUpdated && rect.Contains(Event.current.mousePosition)) { DragAndDrop.visualMode = DragAndDrop.objectReferences.All(obj => TryGetDragAndDropObject(obj, out _)) ? DragAndDropVisualMode.Copy : DragAndDropVisualMode.Rejected; Event.current.Use(); } else if (Event.current.type == EventType.DragPerform && rect.Contains(Event.current.mousePosition)) { DragAndDrop.AcceptDrag(); foreach (var obj in DragAndDrop.objectReferences) { if (TryGetDragAndDropObject(obj, out var addedReferenceValue)) { AddElementCallback(_reorderableListGui, addedReferenceValue); } } Event.current.Use(); } } private void DrawElementBackgroundCallback(Rect rect, int index, bool isActive, bool isFocused) { if (_lastInvisibleElement.HasValue && index + 1 < _lastInvisibleElement.Value || _lastVisibleElement.HasValue && index - 1 > _lastVisibleElement.Value) { if (index != _reorderableListGui.index) { return; } } if (_showAlternatingBackground && index % 2 != 0) { EditorGUI.DrawRect(rect, new Color(0.1f, 0.1f, 0.1f, 0.15f)); } ReorderableList.defaultBehaviours.DrawElementBackground(rect, index, isActive, isFocused, _reorderableListGui.draggable); } private void DrawElementCallback(Rect rect, int index, bool isActive, bool isFocused) { if (index >= ChildrenCount) { return; } if (_lastInvisibleElement.HasValue && index + 1 < _lastInvisibleElement.Value || _lastVisibleElement.HasValue && index - 1 > _lastVisibleElement.Value) { if (index != _reorderableListGui.index) { return; } } if (_reorderableListGui.count > MinElementsForVirtualization) { if (Event.current.type == EventType.Repaint) { var windowRect = GUIClipProxy.VisibleRect; var rectInWindow = GUIClipProxy.UnClipToWindow(rect); if (rectInWindow.yMax < 0) { _lastInvisibleElement = index; } else if (_lastInvisibleElement == index) { _lastInvisibleElement = index / 2; _lastVisibleElement = index / 2 + 1; _property.PropertyTree.RequestRepaint(); } if (rectInWindow.y < windowRect.height) { if (!_lastVisibleElement.HasValue || index > _lastVisibleElement.Value) { _lastVisibleElement = index; } } } } if (!_reorderableListGui.draggable) { rect.xMin += DraggableAreaExtraWidth; } using (TriPropertyOverrideContext.BeginOverride(ListPropertyOverrideContext.Instance)) { GetChild(index).OnGUI(rect); } } private float ElementHeightCallback(int index) { if (index >= ChildrenCount) { return EditorGUIUtility.singleLineHeight; } if (_lastInvisibleElement.HasValue && index + 1 < _lastInvisibleElement.Value || _lastVisibleElement.HasValue && index - 1 > _lastVisibleElement.Value) { if (index != _reorderableListGui.index) { return Mathf.Max(EditorGUIUtility.singleLineHeight, GetChild(index).CachedHeight); } } return GetChild(index).GetHeight(_lastContentWidth); } private static object CreateDefaultElementValue(TriProperty property) { var canActivate = property.ArrayElementType.IsValueType || property.ArrayElementType.GetConstructor(Type.EmptyTypes) != null; return canActivate ? Activator.CreateInstance(property.ArrayElementType) : null; } private static Array CloneValue(TriProperty property) { var list = (IList) property.Value; var template = Array.CreateInstance(property.ArrayElementType, list?.Count ?? 0); list?.CopyTo(template, 0); return template; } private bool TryGetDragAndDropObject(Object obj, out Object result) { if (obj == null) { result = null; return false; } var elementType = _property.ArrayElementType; var objType = obj.GetType(); if (elementType == objType || elementType.IsAssignableFrom(objType)) { result = obj; return true; } if (obj is GameObject go && typeof(Component).IsAssignableFrom(elementType) && go.TryGetComponent(elementType, out var component)) { result = component; return true; } result = null; return false; } private class ListPropertyOverrideContext : TriPropertyOverrideContext { public static readonly ListPropertyOverrideContext Instance = new ListPropertyOverrideContext(); private readonly GUIContent _noneLabel = GUIContent.none; public override bool TryGetDisplayName(TriProperty property, out GUIContent displayName) { var showLabels = property.TryGetAttribute(out ListDrawerSettingsAttribute settings) && settings.ShowElementLabels; if (!showLabels) { displayName = _noneLabel; return true; } displayName = default; return false; } } private static class Styles { public static readonly GUIStyle ItemsCount; static Styles() { ItemsCount = new GUIStyle(GUI.skin.label) { alignment = TextAnchor.MiddleRight, normal = { textColor = EditorGUIUtility.isProSkin ? new Color(0.6f, 0.6f, 0.6f) : new Color(0.3f, 0.3f, 0.3f), }, }; } } } } ================================================ FILE: VirtueSky/Inspector/Editor/Elements/TriListElement.cs.meta ================================================ fileFormatVersion: 2 guid: c9ed87465ed54b039d11e455c4aa3efc timeCreated: 1638776402 ================================================ FILE: VirtueSky/Inspector/Editor/Elements/TriMultiEditNotSupportedElement.cs ================================================ using UnityEditor; using UnityEngine; namespace VirtueSky.Inspector.Elements { public class TriMultiEditNotSupportedElement : TriElement { private readonly TriProperty _property; private readonly GUIContent _message; public TriMultiEditNotSupportedElement(TriProperty property) { _property = property; _message = new GUIContent("Multi edit not supported"); } public override float GetHeight(float width) { return EditorGUIUtility.singleLineHeight; } public override void OnGUI(Rect position) { EditorGUI.LabelField(position, _property.DisplayNameContent, _message); } } } ================================================ FILE: VirtueSky/Inspector/Editor/Elements/TriMultiEditNotSupportedElement.cs.meta ================================================ fileFormatVersion: 2 guid: 575bf0dafd7f459fb09451ec5a83c427 timeCreated: 1641382168 ================================================ FILE: VirtueSky/Inspector/Editor/Elements/TriNoDrawerElement.cs ================================================ using UnityEditor; using UnityEngine; namespace VirtueSky.Inspector.Elements { public class TriNoDrawerElement : TriElement { private readonly GUIContent _message; private readonly TriProperty _property; public TriNoDrawerElement(TriProperty property) { _property = property; _message = new GUIContent($"No drawer for {property.FieldType}"); } public override float GetHeight(float width) { return EditorGUIUtility.singleLineHeight; } public override void OnGUI(Rect position) { EditorGUI.LabelField(position, _property.DisplayNameContent, _message); } } } ================================================ FILE: VirtueSky/Inspector/Editor/Elements/TriNoDrawerElement.cs.meta ================================================ fileFormatVersion: 2 guid: e6cc0cc1449a4af4b8d435b87ef20378 timeCreated: 1639319113 ================================================ FILE: VirtueSky/Inspector/Editor/Elements/TriPropertyCollectionBaseElement.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using JetBrains.Annotations; using VirtueSky.Inspector.Utilities; namespace VirtueSky.Inspector.Elements { public abstract class TriPropertyCollectionBaseElement : TriElement { private List _declarations = new List(); private Dictionary _groups; internal void ClearGroups() { _declarations.Clear(); } [PublicAPI] public void DeclareGroups([CanBeNull] Type type) { if (type == null) { return; } foreach (var attribute in TriReflectionUtilities.GetAttributesCached(type)) { if (attribute is DeclareGroupBaseAttribute declareAttribute) { _declarations.Add(declareAttribute); } } } [PublicAPI] public void AddProperty(TriProperty property) { AddProperty(property, default, out _); } [PublicAPI] public void AddProperty(TriProperty property, TriPropertyElement.Props props, out string group) { var propertyElement = new TriPropertyElement(property, props); if (property.TryGetAttribute(out GroupAttribute groupAttribute)) { IEnumerable path = groupAttribute.Path.Split('/'); var remaining = path.GetEnumerator(); if (remaining.MoveNext()) { group = remaining.Current; AddGroupedChild(propertyElement, property, remaining.Current, remaining.Current, remaining); } else { group = null; AddPropertyChild(propertyElement, property); } } else { group = null; AddPropertyChild(propertyElement, property); } } private void AddGroupedChild(TriElement child, TriProperty property, string currentPath, string currentName, IEnumerator remainingPath) { if (_groups == null) { _groups = new Dictionary(); } var groupElement = CreateSubGroup(property, currentPath, currentName); if (remainingPath.MoveNext()) { var nextPath = currentPath + "/" + remainingPath.Current; var nextName = remainingPath.Current; groupElement.AddGroupedChild(child, property, nextPath, nextName, remainingPath); } else { groupElement.AddPropertyChild(child, property); } } private TriPropertyCollectionBaseElement CreateSubGroup(TriProperty property, string groupPath, string groupName) { if (!_groups.TryGetValue(groupName, out var groupElement)) { var declaration = _declarations.FirstOrDefault(it => it.Path == groupPath); if (declaration != null) { groupElement = TriDrawersUtilities.TryCreateGroupElementFor(declaration); } if (groupElement == null) { groupElement = new DefaultGroupElement(); } groupElement._declarations = _declarations; _groups.Add(groupName, groupElement); AddPropertyChild(groupElement, property); } return groupElement; } protected virtual void AddPropertyChild(TriElement element, TriProperty property) { AddChild(element); } private class DefaultGroupElement : TriPropertyCollectionBaseElement { } } } ================================================ FILE: VirtueSky/Inspector/Editor/Elements/TriPropertyCollectionBaseElement.cs.meta ================================================ fileFormatVersion: 2 guid: 1373b681c88a425c943ea5e6d149a217 timeCreated: 1639412705 ================================================ FILE: VirtueSky/Inspector/Editor/Elements/TriPropertyElement.cs ================================================ using System; using UnityEditor; using UnityEngine; namespace VirtueSky.Inspector.Elements { public class TriPropertyElement : TriElement { private readonly TriProperty _property; [Serializable] public struct Props { public bool forceInline; } public TriPropertyElement(TriProperty property, Props props = default) { _property = property; foreach (var error in _property.ExtensionErrors) { AddChild(new TriInfoBoxElement(error, TriMessageType.Error)); } var element = CreateElement(property, props); var drawers = property.AllDrawers; for (var index = drawers.Count - 1; index >= 0; index--) { element = drawers[index].CreateElementInternal(property, element); } AddChild(element); } public override float GetHeight(float width) { if (!_property.IsVisible) { return -EditorGUIUtility.standardVerticalSpacing; } return base.GetHeight(width); } public override void OnGUI(Rect position) { if (!_property.IsVisible) { return; } var oldShowMixedValue = EditorGUI.showMixedValue; var oldEnabled = GUI.enabled; GUI.enabled &= _property.IsEnabled; EditorGUI.showMixedValue = _property.IsValueMixed; var overrideCtx = TriPropertyOverrideContext.BeginProperty(); if (_property.TryGetSerializedProperty(out var serializedProperty)) { EditorGUI.BeginProperty(position, null, serializedProperty); } base.OnGUI(position); if (_property.TryGetSerializedProperty(out _)) { EditorGUI.EndProperty(); } overrideCtx.EndProperty(); EditorGUI.showMixedValue = oldShowMixedValue; GUI.enabled = oldEnabled; } private static TriElement CreateElement(TriProperty property, Props props) { switch (property.PropertyType) { case TriPropertyType.Array: { return CreateArrayElement(property); } case TriPropertyType.Reference: { return CreateReferenceElement(property, props); } case TriPropertyType.Generic: { return CreateGenericElement(property, props); } default: { return new TriNoDrawerElement(property); } } } private static TriElement CreateArrayElement(TriProperty property) { return new TriListElement(property); } private static TriElement CreateReferenceElement(TriProperty property, Props props) { if (property.TryGetAttribute(out InlinePropertyAttribute inlineAttribute)) { return new TriReferenceElement(property, new TriReferenceElement.Props { inline = true, drawPrefixLabel = !props.forceInline, labelWidth = inlineAttribute.LabelWidth, }); } if (props.forceInline) { return new TriReferenceElement(property, new TriReferenceElement.Props { inline = true, drawPrefixLabel = false, }); } return new TriReferenceElement(property, new TriReferenceElement.Props { inline = false, drawPrefixLabel = false, }); } private static TriElement CreateGenericElement(TriProperty property, Props props) { if (property.TryGetAttribute(out InlinePropertyAttribute inlineAttribute)) { return new TriInlineGenericElement(property, new TriInlineGenericElement.Props { drawPrefixLabel = !props.forceInline, labelWidth = inlineAttribute.LabelWidth, }); } if (props.forceInline) { return new TriInlineGenericElement(property, new TriInlineGenericElement.Props { drawPrefixLabel = false, }); } return new TriFoldoutElement(property); } } } ================================================ FILE: VirtueSky/Inspector/Editor/Elements/TriPropertyElement.cs.meta ================================================ fileFormatVersion: 2 guid: f57a61ef6fe34b51939950c6b9597f88 timeCreated: 1638776439 ================================================ FILE: VirtueSky/Inspector/Editor/Elements/TriReferenceElement.cs ================================================ using System; using VirtueSky.Inspector.Utilities; using UnityEditor; using UnityEngine; namespace VirtueSky.Inspector.Elements { internal class TriReferenceElement : TriPropertyCollectionBaseElement { private readonly Props _props; private readonly TriProperty _property; private readonly bool _showReferencePicker; private readonly bool _skipReferencePickerExtraLine; private Type _referenceType; [Serializable] public struct Props { public bool inline; public bool drawPrefixLabel; public float labelWidth; } public TriReferenceElement(TriProperty property, Props props = default) { _property = property; _props = props; _showReferencePicker = !property.TryGetAttribute(out HideReferencePickerAttribute _); _skipReferencePickerExtraLine = !_showReferencePicker && _props.inline; } public override bool Update() { var dirty = false; if (_props.inline || _property.IsExpanded) { dirty |= GenerateChildren(); } else { dirty |= ClearChildren(); } dirty |= base.Update(); return dirty; } public override float GetHeight(float width) { var height = _skipReferencePickerExtraLine ? 0f : EditorGUIUtility.singleLineHeight; if (_props.inline || _property.IsExpanded) { height += base.GetHeight(width); } return height; } public override void OnGUI(Rect position) { if (_props.drawPrefixLabel) { var controlId = GUIUtility.GetControlID(FocusType.Passive); position = EditorGUI.PrefixLabel(position, controlId, _property.DisplayNameContent); } var headerRect = new Rect(position) { height = _skipReferencePickerExtraLine ? 0f : EditorGUIUtility.singleLineHeight, }; var headerLabelRect = new Rect(position) { height = headerRect.height, width = EditorGUIUtility.labelWidth, }; var headerFieldRect = new Rect(position) { height = headerRect.height, xMin = headerRect.xMin + EditorGUIUtility.labelWidth, }; var contentRect = new Rect(position) { yMin = position.yMin + headerRect.height, }; if (_props.inline) { if (_showReferencePicker) { TriManagedReferenceGui.DrawTypeSelector(headerRect, _property); } using (TriGuiHelper.PushLabelWidth(_props.labelWidth)) { base.OnGUI(contentRect); } } else { TriEditorGUI.Foldout(headerLabelRect, _property); if (_showReferencePicker) { TriManagedReferenceGui.DrawTypeSelector(headerFieldRect, _property); } if (_property.IsExpanded) { using (var indentedRectScope = TriGuiHelper.PushIndentedRect(contentRect, 1)) using (TriGuiHelper.PushLabelWidth(_props.labelWidth)) { base.OnGUI(indentedRectScope.IndentedRect); } } } } private bool GenerateChildren() { if (_property.ValueType == _referenceType) { return false; } _referenceType = _property.ValueType; RemoveAllChildren(); ClearGroups(); DeclareGroups(_property.ValueType); foreach (var childProperty in _property.ChildrenProperties) { AddProperty(childProperty); } return true; } private bool ClearChildren() { if (ChildrenCount == 0) { return false; } _referenceType = null; RemoveAllChildren(); return true; } } } ================================================ FILE: VirtueSky/Inspector/Editor/Elements/TriReferenceElement.cs.meta ================================================ fileFormatVersion: 2 guid: 7dd13898e07a45afacca03cc86c0e24c timeCreated: 1638789498 ================================================ FILE: VirtueSky/Inspector/Editor/Elements/TriTabGroupElement.cs ================================================ using System.Collections.Generic; using VirtueSky.Inspector.Resolvers; using UnityEngine; namespace VirtueSky.Inspector.Elements { public class TriTabGroupElement : TriHeaderGroupBaseElement { private const string DefaultTabName = "Main"; private readonly List _tabs; private readonly Dictionary _tabElements; private string _activeTabName; private struct TabInfo { public string name; public ValueResolver titleResolver; public TriProperty property; } public TriTabGroupElement() { _tabs = new List(); _tabElements = new Dictionary(); _activeTabName = null; } protected override void DrawHeader(Rect position) { if (_tabs.Count == 0) { return; } var tabRect = new Rect(position) { width = position.width / _tabs.Count, }; if (_tabs.Count == 1) { var tab = _tabs[0]; var content = tab.titleResolver.GetValue(tab.property); GUI.Toggle(tabRect, true, content, TriEditorStyles.TabOnlyOne); } else { for (int index = 0, tabCount = _tabs.Count; index < tabCount; index++) { var tab = _tabs[index]; var content = tab.titleResolver.GetValue(tab.property); var tabStyle = index == 0 ? TriEditorStyles.TabFirst : index == tabCount - 1 ? TriEditorStyles.TabLast : TriEditorStyles.TabMiddle; var isTabActive = GUI.Toggle(tabRect, _activeTabName == tab.name, content, tabStyle); if (isTabActive && _activeTabName != tab.name) { SetActiveTab(tab.name); } tabRect.x += tabRect.width; } } } protected override void AddPropertyChild(TriElement element, TriProperty property) { var tabName = DefaultTabName; if (property.TryGetAttribute(out TabAttribute tab)) { tabName = tab.TabName ?? tabName; } if (!_tabElements.TryGetValue(tabName, out var tabElement)) { tabElement = new TriElement(); var info = new TabInfo { name = tabName, titleResolver = ValueResolver.ResolveString(property.Definition, tabName), property = property, }; _tabElements[tabName] = tabElement; _tabs.Add(info); if (info.titleResolver.TryGetErrorString(out var error)) { tabElement.AddChild(new TriInfoBoxElement(error, TriMessageType.Error)); } if (_activeTabName == null) { SetActiveTab(tabName); } } tabElement.AddChild(element); } private void SetActiveTab(string tabName) { _activeTabName = tabName; RemoveAllChildren(); AddChild(_tabElements[_activeTabName]); } } } ================================================ FILE: VirtueSky/Inspector/Editor/Elements/TriTabGroupElement.cs.meta ================================================ fileFormatVersion: 2 guid: deb5a57d2d0a4476a3e396a49b9f44da timeCreated: 1642759023 ================================================ FILE: VirtueSky/Inspector/Editor/Elements/TriUiToolkitPropertyElemenet.cs ================================================ using VirtueSky.InspectorUnityInternalBridge; using UnityEditor; using UnityEditor.UIElements; using UnityEngine; using UnityEngine.UIElements; namespace VirtueSky.Inspector.Elements { public class TriUiToolkitPropertyElement : TriElement { private readonly SerializedProperty _serializedProperty; private readonly VisualElement _rootElement; private readonly VisualElement _selfElement; private bool _heightDirty; public TriUiToolkitPropertyElement( TriProperty property, SerializedProperty serializedProperty, VisualElement selfElement, VisualElement rootElement) { _serializedProperty = serializedProperty; _selfElement = selfElement; _rootElement = rootElement; _selfElement.style.position = Position.Absolute; } protected override void OnAttachToPanel() { base.OnAttachToPanel(); _rootElement.schedule.Execute(() => { _rootElement.Add(_selfElement); _selfElement.Bind(_serializedProperty.serializedObject); }); } protected override void OnDetachFromPanel() { _rootElement.schedule.Execute(() => { _selfElement.Unbind(); _rootElement.Remove(_selfElement); }); base.OnDetachFromPanel(); } public override bool Update() { var dirty = base.Update(); if (_heightDirty) { _heightDirty = false; dirty = true; } return dirty; } public override float GetHeight(float width) { var height = _selfElement.resolvedStyle.height; if (float.IsNaN(height)) { _heightDirty = true; return 0f; } return height; } public override void OnGUI(Rect position) { if (Event.current.type == EventType.Repaint) { var pos = GUIClipProxy.UnClip(position.position); _selfElement.style.width = position.width; _selfElement.style.left = pos.x; _selfElement.style.top = pos.y; } } } } ================================================ FILE: VirtueSky/Inspector/Editor/Elements/TriUiToolkitPropertyElemenet.cs.meta ================================================ fileFormatVersion: 2 guid: 535ce5f65f424a8c9e83943eda845fc6 timeCreated: 1690621289 ================================================ FILE: VirtueSky/Inspector/Editor/Elements/TriVerticalGroupElement.cs ================================================ namespace VirtueSky.Inspector.Elements { public class TriVerticalGroupElement : TriPropertyCollectionBaseElement { } } ================================================ FILE: VirtueSky/Inspector/Editor/Elements/TriVerticalGroupElement.cs.meta ================================================ fileFormatVersion: 2 guid: ec0e2c38af6f4830b3eca87e63c3248c timeCreated: 1643558785 ================================================ FILE: VirtueSky/Inspector/Editor/Elements.meta ================================================ fileFormatVersion: 2 guid: 99d0fe2f9d1c4cb88cf46ba5813c091f timeCreated: 1638772919 ================================================ FILE: VirtueSky/Inspector/Editor/Resolvers/ActionResolver.cs ================================================ using JetBrains.Annotations; namespace VirtueSky.Inspector.Resolvers { public abstract class ActionResolver { public static ActionResolver Resolve(TriPropertyDefinition propertyDefinition, string method) { if (InstanceActionResolver.TryResolve(propertyDefinition, method, out var iar)) { return iar; } return new ErrorActionResolver(propertyDefinition, method); } [PublicAPI] public abstract bool TryGetErrorString(out string error); [PublicAPI] public abstract void InvokeForTarget(TriProperty property, int targetIndex); [PublicAPI] public void InvokeForAllTargets(TriProperty property) { for (var targetIndex = 0; targetIndex < property.PropertyTree.TargetsCount; targetIndex++) { InvokeForTarget(property, targetIndex); } } } } ================================================ FILE: VirtueSky/Inspector/Editor/Resolvers/ActionResolver.cs.meta ================================================ fileFormatVersion: 2 guid: 188152364708438db80df00df894ae87 timeCreated: 1652265564 ================================================ FILE: VirtueSky/Inspector/Editor/Resolvers/DropdownValuesResolver.cs ================================================ using System.Collections.Generic; using System.Linq; using JetBrains.Annotations; namespace VirtueSky.Inspector.Resolvers { public class DropdownValuesResolver { [CanBeNull] private ValueResolver>> _itemsResolver; [CanBeNull] private ValueResolver> _valuesResolver; [PublicAPI] public static DropdownValuesResolver Resolve(TriPropertyDefinition propertyDefinition, string expression) { var valuesResolver = ValueResolver.Resolve>(propertyDefinition, expression); if (!valuesResolver.TryGetErrorString(out _)) { return new DropdownValuesResolver { _valuesResolver = valuesResolver, }; } var itemsResolver = ValueResolver.Resolve>>(propertyDefinition, expression); return new DropdownValuesResolver { _itemsResolver = itemsResolver, }; } [PublicAPI] public bool TryGetErrorString(out string error) { return ValueResolver.TryGetErrorString(_valuesResolver, _itemsResolver, out error); } [PublicAPI] public IEnumerable GetDropdownItems(TriProperty property) { if (_valuesResolver != null) { var values = _valuesResolver.GetValue(property, Enumerable.Empty()); foreach (var value in values) { yield return new TriDropdownItem {Text = $"{value}", Value = value,}; } } if (_itemsResolver != null) { var values = _itemsResolver.GetValue(property, Enumerable.Empty>()); foreach (var value in values) { yield return value; } } } } } ================================================ FILE: VirtueSky/Inspector/Editor/Resolvers/DropdownValuesResolver.cs.meta ================================================ fileFormatVersion: 2 guid: 16fa8c4711a44bdea6facb3bc68822d9 timeCreated: 1680713564 ================================================ FILE: VirtueSky/Inspector/Editor/Resolvers/ErrorActionResolver.cs ================================================ using System; using UnityEngine; namespace VirtueSky.Inspector.Resolvers { internal sealed class ErrorActionResolver : ActionResolver { private readonly string _method; public ErrorActionResolver(TriPropertyDefinition propertyDefinition, string method) { _method = method; } public override bool TryGetErrorString(out string error) { error = $"Method '{_method}' not exists or has wrong signature"; return true; } public override void InvokeForTarget(TriProperty property, int targetIndex) { Debug.LogException(new InvalidOperationException("Method not exists")); } } } ================================================ FILE: VirtueSky/Inspector/Editor/Resolvers/ErrorActionResolver.cs.meta ================================================ fileFormatVersion: 2 guid: 52fddb0e965c4a8e82a2956d2f6ba53b timeCreated: 1652265995 ================================================ FILE: VirtueSky/Inspector/Editor/Resolvers/ErrorValueResolver.cs ================================================ namespace VirtueSky.Inspector.Resolvers { internal class ErrorValueResolver : ValueResolver { private readonly string _expression; public ErrorValueResolver(TriPropertyDefinition propertyDefinition, string expression) { _expression = expression; } public override bool TryGetErrorString(out string error) { error = $"Method '{_expression}' not exists or has wrong signature"; return true; } public override T GetValue(TriProperty property, T defaultValue = default) { return defaultValue; } } } ================================================ FILE: VirtueSky/Inspector/Editor/Resolvers/ErrorValueResolver.cs.meta ================================================ fileFormatVersion: 2 guid: b3b804d7029c42c0b5f5a692281dacbf timeCreated: 1652096547 ================================================ FILE: VirtueSky/Inspector/Editor/Resolvers/InstanceActionResolver.cs ================================================ using System; using System.Reflection; using UnityEngine; namespace VirtueSky.Inspector.Resolvers { internal sealed class InstanceActionResolver : ActionResolver { private readonly MethodInfo _methodInfo; public static bool TryResolve(TriPropertyDefinition propertyDefinition, string method, out ActionResolver resolver) { var parentType = propertyDefinition.OwnerType; if (parentType == null) { resolver = null; return false; } const BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; foreach (var methodInfo in parentType.GetMethods(flags)) { if (methodInfo.Name == method && methodInfo.ReturnType == typeof(void) && methodInfo.GetParameters() is var parameterInfos && parameterInfos.Length == 0) { resolver = new InstanceActionResolver(methodInfo); return true; } } resolver = null; return false; } private InstanceActionResolver(MethodInfo methodInfo) { _methodInfo = methodInfo; } public override bool TryGetErrorString(out string error) { error = ""; return false; } public override void InvokeForTarget(TriProperty property, int targetIndex) { var parentValue = property.Owner.GetValue(targetIndex); try { _methodInfo.Invoke(parentValue, Array.Empty()); } catch (Exception e) { Debug.LogException(e); } } } } ================================================ FILE: VirtueSky/Inspector/Editor/Resolvers/InstanceActionResolver.cs.meta ================================================ fileFormatVersion: 2 guid: 737737f290e8433e9f160970cf996e4c timeCreated: 1652266150 ================================================ FILE: VirtueSky/Inspector/Editor/Resolvers/InstanceFieldValueResolver.cs ================================================ using System; using System.Reflection; using UnityEngine; namespace VirtueSky.Inspector.Resolvers { internal sealed class InstanceFieldValueResolver : ValueResolver { private readonly FieldInfo _fieldInfo; public static bool TryResolve(TriPropertyDefinition propertyDefinition, string expression, out ValueResolver resolver) { var parentType = propertyDefinition.OwnerType; if (parentType == null) { resolver = null; return false; } const BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; foreach (var fieldInfo in parentType.GetFields(flags)) { if (fieldInfo.Name == expression && typeof(T).IsAssignableFrom(fieldInfo.FieldType)) { resolver = new InstanceFieldValueResolver(fieldInfo); return true; } } resolver = null; return false; } private InstanceFieldValueResolver(FieldInfo fieldInfo) { _fieldInfo = fieldInfo; } public override bool TryGetErrorString(out string error) { error = ""; return false; } public override T GetValue(TriProperty property, T defaultValue = default) { var parentValue = property.Owner.GetValue(0); try { return (T) _fieldInfo.GetValue(parentValue); } catch (Exception e) { if (e is TargetInvocationException targetInvocationException) { e = targetInvocationException.InnerException; } Debug.LogException(e); return defaultValue; } } } } ================================================ FILE: VirtueSky/Inspector/Editor/Resolvers/InstanceFieldValueResolver.cs.meta ================================================ fileFormatVersion: 2 guid: 1c19d3705b8f4c9caf951d60efa47acf timeCreated: 1652287302 ================================================ FILE: VirtueSky/Inspector/Editor/Resolvers/InstanceMethodValueResolver.cs ================================================ using System; using System.Reflection; using UnityEngine; namespace VirtueSky.Inspector.Resolvers { internal sealed class InstanceMethodValueResolver : ValueResolver { private readonly MethodInfo _methodInfo; public static bool TryResolve(TriPropertyDefinition propertyDefinition, string expression, out ValueResolver resolver) { var parentType = propertyDefinition.OwnerType; if (parentType == null) { resolver = null; return false; } const BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; foreach (var methodInfo in parentType.GetMethods(flags)) { if (methodInfo.Name == expression && typeof(T).IsAssignableFrom(methodInfo.ReturnType) && methodInfo.GetParameters() is var parameterInfos && parameterInfos.Length == 0) { resolver = new InstanceMethodValueResolver(methodInfo); return true; } } resolver = null; return false; } private InstanceMethodValueResolver(MethodInfo methodInfo) { _methodInfo = methodInfo; } public override bool TryGetErrorString(out string error) { error = ""; return false; } public override T GetValue(TriProperty property, T defaultValue = default) { var parentValue = property.Owner.GetValue(0); try { return (T) _methodInfo.Invoke(parentValue, Array.Empty()); } catch (Exception e) { if (e is TargetInvocationException targetInvocationException) { e = targetInvocationException.InnerException; } Debug.LogException(e); return defaultValue; } } } } ================================================ FILE: VirtueSky/Inspector/Editor/Resolvers/InstanceMethodValueResolver.cs.meta ================================================ fileFormatVersion: 2 guid: cee79123a0e84d5d9795ea92ed1b6d9e timeCreated: 1652097174 ================================================ FILE: VirtueSky/Inspector/Editor/Resolvers/InstancePropertyValueResolver.cs ================================================ using System; using System.Reflection; using UnityEngine; namespace VirtueSky.Inspector.Resolvers { internal sealed class InstancePropertyValueResolver : ValueResolver { private readonly PropertyInfo _propertyInfo; public static bool TryResolve(TriPropertyDefinition propertyDefinition, string expression, out ValueResolver resolver) { var parentType = propertyDefinition.OwnerType; if (parentType == null) { resolver = null; return false; } const BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; foreach (var propertyInfo in parentType.GetProperties(flags)) { if (propertyInfo.Name == expression && typeof(T).IsAssignableFrom(propertyInfo.PropertyType) && propertyInfo.CanRead) { resolver = new InstancePropertyValueResolver(propertyInfo); return true; } } resolver = null; return false; } private InstancePropertyValueResolver(PropertyInfo propertyInfo) { _propertyInfo = propertyInfo; } public override bool TryGetErrorString(out string error) { error = ""; return false; } public override T GetValue(TriProperty property, T defaultValue = default) { var parentValue = property.Owner.GetValue(0); try { return (T) _propertyInfo.GetValue(parentValue); } catch (Exception e) { if (e is TargetInvocationException targetInvocationException) { e = targetInvocationException.InnerException; } Debug.LogException(e); return defaultValue; } } } } ================================================ FILE: VirtueSky/Inspector/Editor/Resolvers/InstancePropertyValueResolver.cs.meta ================================================ fileFormatVersion: 2 guid: 53c22267d5cf488c86afabea3d4613b0 timeCreated: 1652287280 ================================================ FILE: VirtueSky/Inspector/Editor/Resolvers/StaticFieldValueResolver.cs ================================================ using System; using System.Reflection; using VirtueSky.Inspector.Utilities; using UnityEngine; namespace VirtueSky.Inspector.Resolvers { public class StaticFieldValueResolver : ValueResolver { private readonly FieldInfo _fieldInfo; public static bool TryResolve(TriPropertyDefinition propertyDefinition, string expression, out ValueResolver resolver) { var type = propertyDefinition.OwnerType; var fieldName = expression; var separatorIndex = expression.LastIndexOf('.'); if (separatorIndex >= 0) { var className = expression.Substring(0, separatorIndex); fieldName = expression.Substring(separatorIndex + 1); if (!TriReflectionUtilities.TryFindTypeByFullName(className, out type)) { resolver = null; return false; } } if (type == null) { resolver = null; return false; } const BindingFlags flags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; foreach (var fieldInfo in type.GetFields(flags)) { if (fieldInfo.Name == fieldName && typeof(T).IsAssignableFrom(fieldInfo.FieldType)) { resolver = new StaticFieldValueResolver(fieldInfo); return true; } } resolver = null; return false; } public StaticFieldValueResolver(FieldInfo fieldInfo) { _fieldInfo = fieldInfo; } public override bool TryGetErrorString(out string error) { error = ""; return false; } public override T GetValue(TriProperty property, T defaultValue = default) { try { return (T) _fieldInfo.GetValue(null); } catch (Exception e) { if (e is TargetInvocationException targetInvocationException) { e = targetInvocationException.InnerException; } Debug.LogException(e); return defaultValue; } } } } ================================================ FILE: VirtueSky/Inspector/Editor/Resolvers/StaticFieldValueResolver.cs.meta ================================================ fileFormatVersion: 2 guid: bc82b93a5bf949958553418b396127ec timeCreated: 1657955836 ================================================ FILE: VirtueSky/Inspector/Editor/Resolvers/StaticMethodValueResolver.cs ================================================ using System; using System.Reflection; using VirtueSky.Inspector.Utilities; using UnityEngine; namespace VirtueSky.Inspector.Resolvers { public class StaticMethodValueResolver : ValueResolver { private readonly MethodInfo _methodInfo; public static bool TryResolve(TriPropertyDefinition propertyDefinition, string expression, out ValueResolver resolver) { var type = propertyDefinition.OwnerType; var methodName = expression; var separatorIndex = expression.LastIndexOf('.'); if (separatorIndex >= 0) { var className = expression.Substring(0, separatorIndex); methodName = expression.Substring(separatorIndex + 1); if (!TriReflectionUtilities.TryFindTypeByFullName(className, out type)) { resolver = null; return false; } } if (type == null) { resolver = null; return false; } const BindingFlags flags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; foreach (var methodInfo in type.GetMethods(flags)) { if (methodInfo.Name == methodName && typeof(T).IsAssignableFrom(methodInfo.ReturnType) && methodInfo.GetParameters() is var parametersInfo && parametersInfo.Length == 0) { resolver = new StaticMethodValueResolver(methodInfo); return true; } } resolver = null; return false; } public StaticMethodValueResolver(MethodInfo methodInfo) { _methodInfo = methodInfo; } public override bool TryGetErrorString(out string error) { error = ""; return false; } public override T GetValue(TriProperty property, T defaultValue = default) { try { return (T) _methodInfo.Invoke(null, null); } catch (Exception e) { if (e is TargetInvocationException targetInvocationException) { e = targetInvocationException.InnerException; } Debug.LogException(e); return defaultValue; } } } } ================================================ FILE: VirtueSky/Inspector/Editor/Resolvers/StaticMethodValueResolver.cs.meta ================================================ fileFormatVersion: 2 guid: 96c731e2cdce45da8ee4be44ce6674ea timeCreated: 1657954360 ================================================ FILE: VirtueSky/Inspector/Editor/Resolvers/StaticPropertyValueResolver.cs ================================================ using System; using System.Reflection; using VirtueSky.Inspector.Utilities; using UnityEngine; namespace VirtueSky.Inspector.Resolvers { public class StaticPropertyValueResolver : ValueResolver { private readonly PropertyInfo _propertyInfo; public static bool TryResolve(TriPropertyDefinition propertyDefinition, string expression, out ValueResolver resolver) { var type = propertyDefinition.OwnerType; var propertyName = expression; var separatorIndex = expression.LastIndexOf('.'); if (separatorIndex >= 0) { var className = expression.Substring(0, separatorIndex); propertyName = expression.Substring(separatorIndex + 1); if (!TriReflectionUtilities.TryFindTypeByFullName(className, out type)) { resolver = null; return false; } } if (type == null) { resolver = null; return false; } const BindingFlags flags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; foreach (var propertyInfo in type.GetProperties(flags)) { if (propertyInfo.Name == propertyName && typeof(T).IsAssignableFrom(propertyInfo.PropertyType) && propertyInfo.CanRead) { resolver = new StaticPropertyValueResolver(propertyInfo); return true; } } resolver = null; return false; } public StaticPropertyValueResolver(PropertyInfo propertyInfo) { _propertyInfo = propertyInfo; } public override bool TryGetErrorString(out string error) { error = ""; return false; } public override T GetValue(TriProperty property, T defaultValue = default) { try { return (T) _propertyInfo.GetValue(null); } catch (Exception e) { if (e is TargetInvocationException targetInvocationException) { e = targetInvocationException.InnerException; } Debug.LogException(e); return defaultValue; } } } } ================================================ FILE: VirtueSky/Inspector/Editor/Resolvers/StaticPropertyValueResolver.cs.meta ================================================ fileFormatVersion: 2 guid: 8cbab37d02e54764a8b1ae73eac12d8a timeCreated: 1657955361 ================================================ FILE: VirtueSky/Inspector/Editor/Resolvers/ValueResolver.cs ================================================ using JetBrains.Annotations; namespace VirtueSky.Inspector.Resolvers { public static class ValueResolver { public static ValueResolver Resolve(TriPropertyDefinition propertyDefinition, string expression) { if (expression != null && expression.StartsWith("$")) { expression = expression.Substring(1); } if (StaticFieldValueResolver.TryResolve(propertyDefinition, expression, out var sfr)) { return sfr; } if (StaticPropertyValueResolver.TryResolve(propertyDefinition, expression, out var spr)) { return spr; } if (StaticMethodValueResolver.TryResolve(propertyDefinition, expression, out var smr)) { return smr; } if (InstanceFieldValueResolver.TryResolve(propertyDefinition, expression, out var ifr)) { return ifr; } if (InstancePropertyValueResolver.TryResolve(propertyDefinition, expression, out var ipr)) { return ipr; } if (InstanceMethodValueResolver.TryResolve(propertyDefinition, expression, out var imr)) { return imr; } return new ErrorValueResolver(propertyDefinition, expression); } public static ValueResolver ResolveString(TriPropertyDefinition propertyDefinition, string expression) { if (expression != null && expression.StartsWith("$")) { return Resolve(propertyDefinition, expression.Substring(1)); } return new ConstantValueResolver(expression); } public static bool TryGetErrorString([CanBeNull] ValueResolver resolver, out string error) { return TryGetErrorString(resolver, null, out error); } public static bool TryGetErrorString(ValueResolver resolver1, ValueResolver resolver2, out string error) { if (resolver1 != null && resolver1.TryGetErrorString(out var error1)) { error = error1; return true; } if (resolver2 != null && resolver2.TryGetErrorString(out var error2)) { error = error2; return true; } error = null; return false; } } public abstract class ValueResolver { [PublicAPI] public abstract bool TryGetErrorString(out string error); [PublicAPI] public abstract T GetValue(TriProperty property, T defaultValue = default); } public sealed class ConstantValueResolver : ValueResolver { private readonly T _value; public ConstantValueResolver(T value) { _value = value; } public override bool TryGetErrorString(out string error) { error = default; return false; } public override T GetValue(TriProperty property, T defaultValue = default) { return _value; } } } ================================================ FILE: VirtueSky/Inspector/Editor/Resolvers/ValueResolver.cs.meta ================================================ fileFormatVersion: 2 guid: 467299addfb7498fbb7e7f0e449c4364 timeCreated: 1652095635 ================================================ FILE: VirtueSky/Inspector/Editor/Resolvers.meta ================================================ fileFormatVersion: 2 guid: ca8a2709dde94e318cb5cfdc801d9045 timeCreated: 1652095622 ================================================ FILE: VirtueSky/Inspector/Editor/Resources/TriInspector_Box_Bg.png.meta ================================================ fileFormatVersion: 2 guid: 7a524300faaf5aa40a2ff59c25b28b71 TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 11 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 1 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 0 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 8 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 3 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 3 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: 5e97eb03825dee720800000000000000 internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] spritePackingTag: pSDRemoveMatte: 0 pSDShowRemoveMatteOption: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Inspector/Editor/Resources/TriInspector_Box_Bg_Dark.png.meta ================================================ fileFormatVersion: 2 guid: 6c3f6c6cd431e8e4e87094572f59d524 TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 11 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 1 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 0 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 8 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 3 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 3 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: 5e97eb03825dee720800000000000000 internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] spritePackingTag: pSDRemoveMatte: 0 pSDShowRemoveMatteOption: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Inspector/Editor/Resources/TriInspector_Content_Bg.png.meta ================================================ fileFormatVersion: 2 guid: 372e4831c9374244aafdd096c36bb645 TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 11 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 1 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 0 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 8 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 3 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 3 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: 5e97eb03825dee720800000000000000 internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] spritePackingTag: pSDRemoveMatte: 0 pSDShowRemoveMatteOption: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Inspector/Editor/Resources/TriInspector_Content_Bg_Dark.png.meta ================================================ fileFormatVersion: 2 guid: d73be6aba60ae5b41887b4116facc353 TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 11 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 1 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 0 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 8 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 3 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 3 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: 5e97eb03825dee720800000000000000 internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] spritePackingTag: pSDRemoveMatte: 0 pSDShowRemoveMatteOption: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Inspector/Editor/Resources.meta ================================================ fileFormatVersion: 2 guid: d8d4d0876dcc071428509b59e2f78e29 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Inspector/Editor/TriAttributeDrawer.cs ================================================ using System; using JetBrains.Annotations; using UnityEngine; namespace VirtueSky.Inspector { public abstract class TriAttributeDrawer : TriCustomDrawer { internal Attribute RawAttribute { get; set; } } public abstract class TriAttributeDrawer : TriAttributeDrawer where TAttribute : Attribute { [PublicAPI] public TAttribute Attribute => (TAttribute) RawAttribute; public sealed override TriElement CreateElementInternal(TriProperty property, TriElement next) { return CreateElement(property, next); } [PublicAPI] public virtual TriElement CreateElement(TriProperty property, TriElement next) { return new DefaultAttributeDrawerElement(this, property, next); } [PublicAPI] public virtual float GetHeight(float width, TriProperty property, TriElement next) { return next.GetHeight(width); } [PublicAPI] public virtual void OnGUI(Rect position, TriProperty property, TriElement next) { next.OnGUI(position); } internal class DefaultAttributeDrawerElement : TriElement { private readonly TriAttributeDrawer _drawer; private readonly TriElement _next; private readonly TriProperty _property; public DefaultAttributeDrawerElement(TriAttributeDrawer drawer, TriProperty property, TriElement next) { _drawer = drawer; _property = property; _next = next; AddChild(next); } public override float GetHeight(float width) { return _drawer.GetHeight(width, _property, _next); } public override void OnGUI(Rect position) { _drawer.OnGUI(position, _property, _next); } } } } ================================================ FILE: VirtueSky/Inspector/Editor/TriAttributeDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: 31f59a1db97a4d389263665aaf9bccf1 timeCreated: 1639381350 ================================================ FILE: VirtueSky/Inspector/Editor/TriCustomDrawer.cs ================================================ namespace VirtueSky.Inspector { public abstract class TriCustomDrawer : TriPropertyExtension { internal int Order { get; set; } public abstract TriElement CreateElementInternal(TriProperty property, TriElement next); } } ================================================ FILE: VirtueSky/Inspector/Editor/TriCustomDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: 896bcecdfc7048de8375841799d14ecc timeCreated: 1638885450 ================================================ FILE: VirtueSky/Inspector/Editor/TriDrawerOrder.cs ================================================ namespace VirtueSky.Inspector { public static class TriDrawerOrder { public const int System = -9999; public const int Inspector = -2000; public const int Validator = -1500; public const int Decorator = -1000; public const int Drawer = 0; public const int Fallback = 9999; } } ================================================ FILE: VirtueSky/Inspector/Editor/TriDrawerOrder.cs.meta ================================================ fileFormatVersion: 2 guid: 2db5b837fe8643de8e5be9eaee10f509 timeCreated: 1639384181 ================================================ FILE: VirtueSky/Inspector/Editor/TriEditorStyles.cs ================================================ using UnityEditor; using UnityEngine; namespace VirtueSky.Inspector { public static class TriEditorStyles { private static GUIStyle _contentBox; private static GUIStyle _box; public static GUIStyle TabOnlyOne { get; } = "Tab onlyOne"; public static GUIStyle TabFirst { get; } = "Tab first"; public static GUIStyle TabMiddle { get; } = "Tab middle"; public static GUIStyle TabLast { get; } = "Tab last"; private static GUIStyle FallbackContentBox { get; } = "HelpBox"; private static GUIStyle FallbackBox { get; } = "HelpBox"; public static GUIStyle ContentBox { get { if (_contentBox == null) { var backgroundTexture = LoadTexture("TriInspector_Content_Bg"); if (backgroundTexture == null) { _contentBox = new GUIStyle(FallbackContentBox); } else { _contentBox = new GUIStyle { normal = { background = backgroundTexture, }, }; } _contentBox.border = new RectOffset(2, 2, 2, 2); } return _contentBox; } } public static GUIStyle Box { get { if (_box == null) { var backgroundTexture = LoadTexture("TriInspector_Box_Bg"); if (backgroundTexture == null) { _box = new GUIStyle(FallbackBox); } else { _box = new GUIStyle { normal = { background = backgroundTexture, }, }; } _box.border = new RectOffset(2, 2, 2, 2); } return _box; } } private static Texture2D LoadTexture(string name) { name = EditorGUIUtility.isProSkin ? $"{name}_Dark" : name; var results = AssetDatabase.FindAssets($"{name} t:texture2D"); if (results.Length == 0) return null; var path = AssetDatabase.GUIDToAssetPath(results[0]); return (Texture2D) EditorGUIUtility.Load(path); } } } ================================================ FILE: VirtueSky/Inspector/Editor/TriEditorStyles.cs.meta ================================================ fileFormatVersion: 2 guid: 6f23eb6fd2f644a0a718543287192636 timeCreated: 1639462144 ================================================ FILE: VirtueSky/Inspector/Editor/TriElement.cs ================================================ using System.Collections.Generic; using JetBrains.Annotations; using UnityEditor; using UnityEngine; namespace VirtueSky.Inspector { public class TriElement { private static readonly List Empty = new List(); private float _cachedHeight; private bool _cachedheightDirty; private bool _attached; private List _children = Empty; [PublicAPI] public int ChildrenCount => _children.Count; public bool IsAttached => _attached; internal float CachedHeight => _cachedHeight; [PublicAPI] public virtual bool Update() { if (!_attached) { Debug.LogError($"{GetType().Name} not attached"); } var dirty = false; foreach (var child in _children) { dirty |= child.Update(); } return dirty; } [PublicAPI] public virtual float GetHeight(float width) { if (!_attached) { Debug.LogError($"{GetType().Name} not attached"); } if (Event.current.type != EventType.Layout && !_cachedheightDirty) { return _cachedHeight; } _cachedheightDirty = false; switch (_children.Count) { case 0: return _cachedHeight = 0f; case 1: return _cachedHeight = _children[0].GetHeight(width); default: { _cachedHeight = (_children.Count - 1) * EditorGUIUtility.standardVerticalSpacing; foreach (var child in _children) { _cachedHeight += child.GetHeight(width); } return _cachedHeight; } } } [PublicAPI] public virtual void OnGUI(Rect position) { if (!_attached) { Debug.LogError($"{GetType().Name} not attached"); } switch (_children.Count) { case 0: break; case 1: _children[0].OnGUI(position); break; default: { var offset = 0f; var spacing = EditorGUIUtility.standardVerticalSpacing; foreach (var child in _children) { var childHeight = child.GetHeight(position.width); child.OnGUI(new Rect(position.x, position.y + offset, position.width, childHeight)); offset += childHeight + spacing; } break; } } } [PublicAPI] public TriElement GetChild(int index) { return _children[index]; } [PublicAPI] public void RemoveChildAt(int index) { if (_children.Count < index) { return; } var child = _children[index]; _children.RemoveAt(index); _cachedheightDirty = true; if (_attached) { child.DetachInternal(); } } [PublicAPI] public void RemoveAllChildren() { if (_attached) { foreach (var child in _children) { child.DetachInternal(); } } _children.Clear(); _cachedheightDirty = true; } [PublicAPI] public void AddChild(TriElement child) { if (_children == Empty) { _children = new List(); } _children.Add(child); _cachedheightDirty = true; if (_attached) { child.AttachInternal(); child.Update(); } } internal void AttachInternal() { if (_attached) { Debug.LogError($"{GetType().Name} already attached"); } _attached = true; OnAttachToPanel(); foreach (var child in _children) { child.AttachInternal(); child.Update(); } } internal void DetachInternal() { if (!_attached) { Debug.LogError($"{GetType().Name} not attached"); } _attached = false; foreach (var child in _children) { child.DetachInternal(); } OnDetachFromPanel(); } protected virtual void OnAttachToPanel() { } protected virtual void OnDetachFromPanel() { } } } ================================================ FILE: VirtueSky/Inspector/Editor/TriElement.cs.meta ================================================ fileFormatVersion: 2 guid: 543813bc0e9e4045904a35ef56ea6abe timeCreated: 1638771508 ================================================ FILE: VirtueSky/Inspector/Editor/TriGroupDrawer.cs ================================================ using System; using JetBrains.Annotations; using VirtueSky.Inspector.Elements; namespace VirtueSky.Inspector { public abstract class TriGroupDrawer { public abstract TriPropertyCollectionBaseElement CreateElementInternal(Attribute attribute); } public abstract class TriGroupDrawer : TriGroupDrawer where TAttribute : Attribute { public sealed override TriPropertyCollectionBaseElement CreateElementInternal(Attribute attribute) { return CreateElement((TAttribute) attribute); } [PublicAPI] public abstract TriPropertyCollectionBaseElement CreateElement(TAttribute attribute); } } ================================================ FILE: VirtueSky/Inspector/Editor/TriGroupDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: c7337ea7305e4a5681ff404a041dc93e timeCreated: 1639417787 ================================================ FILE: VirtueSky/Inspector/Editor/TriProperty.cs ================================================ using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; using JetBrains.Annotations; using VirtueSky.Inspector.Utilities; using UnityEditor; using UnityEngine; namespace VirtueSky.Inspector { public sealed class TriProperty { private static readonly StringBuilder SharedPropertyPathStringBuilder = new StringBuilder(); private static readonly IReadOnlyList EmptyValidationResults = new List(); private readonly TriPropertyDefinition _definition; private readonly int _propertyIndex; [CanBeNull] private readonly SerializedObject _serializedObject; [CanBeNull] private readonly SerializedProperty _serializedProperty; private List _childrenProperties; private List _validationResults; private GUIContent _displayNameBackingField; private string _propertyPath; private string _isExpandedPrefsKey; private int _lastUpdateFrame; private bool _isUpdating; [CanBeNull] private object _value; [CanBeNull] private Type _valueType; private bool _isValueMixed; public event Action ValueChanged; public event Action ChildValueChanged; public TriProperty( TriPropertyTree propertyTree, TriProperty parent, TriPropertyDefinition definition, SerializedObject serializedObject ) { Parent = parent; _definition = definition; _propertyIndex = -1; _serializedProperty = null; _serializedObject = serializedObject; PropertyTree = propertyTree; PropertyType = GetPropertyType(this); } public TriProperty( TriPropertyTree propertyTree, TriProperty parent, TriPropertyDefinition definition, int propertyIndex, [CanBeNull] SerializedProperty serializedProperty) { Parent = parent; _definition = definition; _propertyIndex = propertyIndex; _serializedProperty = serializedProperty?.Copy(); _serializedObject = _serializedProperty?.serializedObject; PropertyTree = propertyTree; PropertyType = GetPropertyType(this); } internal TriPropertyDefinition Definition => _definition; [PublicAPI] public TriPropertyType PropertyType { get; } [PublicAPI] public TriPropertyTree PropertyTree { get; } [PublicAPI] public TriProperty Parent { get; } [PublicAPI] public TriProperty Owner => IsArrayElement ? Parent.Owner : Parent; [PublicAPI] public bool IsRootProperty => Parent == null; [PublicAPI] public string RawName => _definition.Name; [PublicAPI] public string DisplayName => DisplayNameContent.text; public IEqualityComparer Comparer => TriEqualityComparer.Of(ValueType); [PublicAPI] public GUIContent DisplayNameContent { get { if (TriPropertyOverrideContext.Current != null && TriPropertyOverrideContext.Current.TryGetDisplayName(this, out var overrideName)) { return overrideName; } if (_displayNameBackingField == null) { if (TryGetAttribute(out HideLabelAttribute _) || IsArrayElement) { _displayNameBackingField = new GUIContent(""); } else { _displayNameBackingField = new GUIContent(ObjectNames.NicifyVariableName(_definition.Name)); } } if (IsArrayElement) { if (TriUnityInspectorUtilities.TryGetSpecialArrayElementName(this, out var specialName)) { _displayNameBackingField.text = specialName; } else { _displayNameBackingField.text = TriUnityInspectorUtilities.GetStandardArrayElementName(this); } } else { if (_definition.CustomLabel != null) { _displayNameBackingField.text = _definition.CustomLabel.GetValue(this, ""); } if (_definition.CustomTooltip != null) { _displayNameBackingField.tooltip = _definition.CustomTooltip.GetValue(this, ""); } } return _displayNameBackingField; } } [PublicAPI] public string PropertyPath { get { if (_propertyPath == null) { SharedPropertyPathStringBuilder.Clear(); BuildPropertyPath(this, SharedPropertyPathStringBuilder); _propertyPath = SharedPropertyPathStringBuilder.ToString(); } return _propertyPath; } } [PublicAPI] public bool IsVisible { get { foreach (var processor in _definition.HideProcessors) { if (processor.IsHidden(this)) { return false; } } return true; } } [PublicAPI] public bool IsEnabled { get { if (_definition.IsReadOnly) { return false; } foreach (var processor in _definition.DisableProcessors) { if (processor.IsDisabled(this)) { return false; } } return true; } } [PublicAPI] public Type FieldType => _definition.FieldType; [PublicAPI] public Type ArrayElementType => _definition.ArrayElementType; [PublicAPI] public bool IsArrayElement => _definition.IsArrayElement; [PublicAPI] public bool IsArray => _definition.IsArray; public int IndexInArray => IsArrayElement ? _propertyIndex : throw new InvalidOperationException("Cannot read IndexInArray for !IsArrayElement"); public IReadOnlyList AllDrawers => _definition.Drawers; internal IReadOnlyList ExtensionErrors => _definition.ExtensionErrors; public bool HasValidators => _definition.Validators.Count != 0; public IReadOnlyList ValidationResults => _validationResults ?? EmptyValidationResults; [PublicAPI] public bool IsExpanded { get { if (_serializedProperty != null) { return _serializedProperty.isExpanded; } if (_isExpandedPrefsKey == null) { _isExpandedPrefsKey = $"TriInspector.expanded.{PropertyPath}"; } return SessionState.GetBool(_isExpandedPrefsKey, false); } set { if (IsExpanded == value) { return; } if (_serializedProperty != null) { _serializedProperty.isExpanded = value; } else if (_isExpandedPrefsKey != null) { SessionState.SetBool(_isExpandedPrefsKey, value); } } } [PublicAPI] [CanBeNull] public Type ValueType { get { if (PropertyType != TriPropertyType.Reference) { return _definition.FieldType; } UpdateIfRequired(); return _valueType; } } public bool IsValueMixed { get { if (PropertyTree.TargetsCount == 1) { return false; } UpdateIfRequired(); return _isValueMixed; } } [PublicAPI] [CanBeNull] public object Value { get { UpdateIfRequired(); return _value; } } [PublicAPI] public IReadOnlyList ChildrenProperties { get { if (_childrenProperties != null && PropertyType == TriPropertyType.Generic) { return _childrenProperties; } UpdateIfRequired(); return PropertyType == TriPropertyType.Generic || PropertyType == TriPropertyType.Reference ? _childrenProperties : throw new InvalidOperationException("Cannot read ChildrenProperties for " + PropertyType); } } [PublicAPI] public IReadOnlyList ArrayElementProperties { get { UpdateIfRequired(); return PropertyType == TriPropertyType.Array ? _childrenProperties : throw new InvalidOperationException("Cannot read ArrayElementProperties for " + PropertyType); } } [PublicAPI] public bool TryGetMemberInfo(out MemberInfo memberInfo) { return _definition.TryGetMemberInfo(out memberInfo); } public object GetValue(int targetIndex) { return _definition.GetValue(this, targetIndex); } [PublicAPI] public void SetValue(object value) { ModifyAndRecordForUndo(targetIndex => SetValueRecursive(this, value, targetIndex)); } [PublicAPI] public void SetValues(Func getValue) { ModifyAndRecordForUndo(targetIndex => { var value = getValue.Invoke(targetIndex); SetValueRecursive(this, value, targetIndex); }); } public void ModifyAndRecordForUndo(Action call) { PropertyTree.ApplyChanges(); PropertyTree.ForceCreateUndoGroup(); for (var targetIndex = 0; targetIndex < PropertyTree.TargetsCount; targetIndex++) { call.Invoke(targetIndex); } PropertyTree.Update(forceUpdate: true); NotifyValueChanged(); PropertyTree.RequestValidation(); PropertyTree.RequestRepaint(); } public void NotifyValueChanged() { NotifyValueChanged(this); } private void NotifyValueChanged(TriProperty property) { if (property == this) { ValueChanged?.Invoke(property); } else { ChildValueChanged?.Invoke(property); } Parent?.NotifyValueChanged(property); } private void UpdateIfRequired(bool forceUpdate = false) { if (_isUpdating) { throw new InvalidOperationException("Recursive call detected"); } if (_lastUpdateFrame == PropertyTree.RepaintFrame && !forceUpdate) { return; } _isUpdating = true; try { _lastUpdateFrame = PropertyTree.RepaintFrame; ReadValue(this, out var newValue, out var newValueIsMixed); var newValueType = FieldType.IsValueType ? FieldType : ReferenceEquals(_value, newValue) ? _valueType : newValue?.GetType(); var valueTypeChanged = _valueType != newValueType; _value = newValue; _valueType = newValueType; _isValueMixed = newValueIsMixed; switch (PropertyType) { case TriPropertyType.Generic: case TriPropertyType.Reference: if (_childrenProperties == null || valueTypeChanged) { if (_childrenProperties == null) { _childrenProperties = new List(); } _childrenProperties.Clear(); var selfType = PropertyType == TriPropertyType.Reference ? _valueType : FieldType; if (selfType != null) { var properties = TriTypeDefinition.GetCached(selfType).Properties; for (var index = 0; index < properties.Count; index++) { var childDefinition = properties[index]; var childSerializedProperty = _serializedProperty != null ? _serializedProperty.FindPropertyRelative(childDefinition.Name) : _serializedObject?.FindProperty(childDefinition.Name); var childProperty = new TriProperty(PropertyTree, this, childDefinition, index, childSerializedProperty); _childrenProperties.Add(childProperty); } } } break; case TriPropertyType.Array: if (_childrenProperties == null) { _childrenProperties = new List(); } var listSize = ((IList)newValue)?.Count ?? 0; while (_childrenProperties.Count < listSize) { var index = _childrenProperties.Count; var elementDefinition = _definition.ArrayElementDefinition; var elementSerializedReference = _serializedProperty?.GetArrayElementAtIndex(index); var elementProperty = new TriProperty(PropertyTree, this, elementDefinition, index, elementSerializedReference); _childrenProperties.Add(elementProperty); } while (_childrenProperties.Count > listSize) { _childrenProperties.RemoveAt(_childrenProperties.Count - 1); } break; } } finally { _isUpdating = false; } } internal void RunValidation() { UpdateIfRequired(); if (HasValidators) { _validationResults = _definition.Validators .Select(it => it.Validate(this)) .Where(it => !it.IsValid) .ToList(); } if (_childrenProperties != null) { foreach (var childrenProperty in _childrenProperties) { childrenProperty.RunValidation(); } } } internal void EnumerateValidationResults(Action call) { UpdateIfRequired(); if (_validationResults != null) { foreach (var result in _validationResults) { call.Invoke(this, result); } } if (_childrenProperties != null) { foreach (var childrenProperty in _childrenProperties) { childrenProperty.EnumerateValidationResults(call); } } } [PublicAPI] public bool TryGetSerializedProperty(out SerializedProperty serializedProperty) { serializedProperty = _serializedProperty; return serializedProperty != null; } [PublicAPI] public bool TryGetAttribute(out TAttribute attribute) where TAttribute : Attribute { if (ValueType != null) { foreach (var attr in TriReflectionUtilities.GetAttributesCached(ValueType)) { if (attr is TAttribute typedAttr) { attribute = typedAttr; return true; } } } foreach (var attr in _definition.Attributes) { if (attr is TAttribute typedAttr) { attribute = typedAttr; return true; } } attribute = null; return false; } internal static void BuildPropertyPath(TriProperty property, StringBuilder sb) { if (property.IsRootProperty) { return; } if (property.Parent != null && !property.Parent.IsRootProperty) { BuildPropertyPath(property.Parent, sb); sb.Append('.'); } if (property.IsArrayElement) { sb.Append("Array.data[").Append(property.IndexInArray).Append(']'); } else { sb.Append(property.RawName); } } private static void SetValueRecursive(TriProperty property, object value, int targetIndex) { // for value types we must recursively set all parent objects // because we cannot directly modify structs // but we can re-set entire parent value while (property._definition.SetValue(property, value, targetIndex, out var parentValue) && property.Parent != null) { property = property.Parent; value = parentValue; } } private static void ReadValue(TriProperty property, out object newValue, out bool isMixed) { newValue = property.GetValue(0); if (property.PropertyTree.TargetsCount == 1) { isMixed = false; return; } switch (property.PropertyType) { case TriPropertyType.Array: { var list = (IList)newValue; for (var i = 1; i < property.PropertyTree.TargetsCount; i++) { if (list == null) { break; } var otherList = (IList)property.GetValue(i); if (otherList == null || otherList.Count < list.Count) { newValue = list = otherList; } } isMixed = true; return; } case TriPropertyType.Reference: { for (var i = 1; i < property.PropertyTree.TargetsCount; i++) { var otherValue = property.GetValue(i); if (newValue?.GetType() != otherValue?.GetType()) { isMixed = true; newValue = null; return; } } isMixed = false; return; } case TriPropertyType.Generic: { isMixed = false; return; } case TriPropertyType.Primitive: { for (var i = 1; i < property.PropertyTree.TargetsCount; i++) { var otherValue = property.GetValue(i); if (!property.Comparer.Equals(otherValue, newValue)) { isMixed = true; return; } } isMixed = false; return; } default: { Debug.LogError($"Unexpected property type: {property.PropertyType}"); isMixed = true; return; } } } private static TriPropertyType GetPropertyType(TriProperty property) { if (property._serializedProperty != null) { if (property._serializedProperty.isArray && property._serializedProperty.propertyType != SerializedPropertyType.String) { return TriPropertyType.Array; } if (property._serializedProperty.propertyType == SerializedPropertyType.ManagedReference) { return TriPropertyType.Reference; } if (property._serializedProperty.propertyType == SerializedPropertyType.Generic) { return TriPropertyType.Generic; } return TriPropertyType.Primitive; } if (property._serializedObject != null) { return TriPropertyType.Generic; } if (property._definition.FieldType.IsPrimitive || property._definition.FieldType == typeof(string) || typeof(UnityEngine.Object).IsAssignableFrom(property._definition.FieldType)) { return TriPropertyType.Primitive; } if (property._definition.FieldType.IsValueType) { return TriPropertyType.Generic; } if (property._definition.IsArray) { return TriPropertyType.Array; } return TriPropertyType.Reference; } } public enum TriPropertyType { Array, Reference, Generic, Primitive, } } ================================================ FILE: VirtueSky/Inspector/Editor/TriProperty.cs.meta ================================================ fileFormatVersion: 2 guid: 4db12eccd9e84863a9b3b445ce3ac85e timeCreated: 1638862848 ================================================ FILE: VirtueSky/Inspector/Editor/TriPropertyDefinition.cs ================================================ using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Reflection; using JetBrains.Annotations; using VirtueSky.Inspector.Resolvers; using VirtueSky.Inspector.Utilities; using UnityEngine; namespace VirtueSky.Inspector { public class TriPropertyDefinition { private readonly ValueGetterDelegate _valueGetter; [CanBeNull] private readonly ValueSetterDelegate _valueSetter; private readonly List _extensionErrors = new List(); private readonly MemberInfo _memberInfo; private readonly List _attributes; private readonly bool _skipNullValuesFix; private TriPropertyDefinition _arrayElementDefinitionBackingField; private IReadOnlyList _drawersBackingField; private IReadOnlyList _validatorsBackingField; private IReadOnlyList _hideProcessorsBackingField; private IReadOnlyList _disableProcessorsBackingField; public static TriPropertyDefinition CreateForFieldInfo(int order, FieldInfo fi) { return CreateForMemberInfo(fi, order, fi.Name, fi.FieldType, MakeGetter(fi), MakeSetter(fi)); } public static TriPropertyDefinition CreateForPropertyInfo(int order, PropertyInfo pi) { return CreateForMemberInfo(pi, order, pi.Name, pi.PropertyType, MakeGetter(pi), MakeSetter(pi)); } public static TriPropertyDefinition CreateForMethodInfo(int order, MethodInfo mi) { return CreateForMemberInfo(mi, order, mi.Name, typeof(MethodInfo), MakeGetter(mi), MakeSetter(mi)); } private static TriPropertyDefinition CreateForMemberInfo( MemberInfo memberInfo, int order, string propertyName, Type propertyType, ValueGetterDelegate valueGetter, ValueSetterDelegate valueSetter) { var attributes = memberInfo?.GetCustomAttributes().ToList(); var ownerType = memberInfo?.DeclaringType ?? typeof(object); return new TriPropertyDefinition( memberInfo, ownerType, order, propertyName, propertyType, valueGetter, valueSetter, attributes, false); } public static TriPropertyDefinition CreateForGetterSetter( int order, string name, Type fieldType, ValueGetterDelegate valueGetter, ValueSetterDelegate valueSetter) { return new TriPropertyDefinition( null, null, order, name, fieldType, valueGetter, valueSetter, null, false); } internal TriPropertyDefinition( MemberInfo memberInfo, Type ownerType, int order, string fieldName, Type fieldType, ValueGetterDelegate valueGetter, ValueSetterDelegate valueSetter, List attributes, bool isArrayElement) { OwnerType = ownerType; Name = fieldName; FieldType = fieldType; IsArrayElement = isArrayElement; _attributes = attributes ?? new List(); _memberInfo = memberInfo; _valueGetter = valueGetter; _valueSetter = valueSetter; _skipNullValuesFix = memberInfo != null && memberInfo.GetCustomAttribute() != null; Order = order; IsReadOnly = _valueSetter == null || Attributes.TryGet(out ReadOnlyAttribute _); if (TriReflectionUtilities.IsArrayOrList(FieldType, out var elementType)) { IsArray = true; ArrayElementType = elementType; } if (Attributes.TryGet(out LabelTextAttribute labelTextAttribute)) { CustomLabel = ValueResolver.ResolveString(this, labelTextAttribute.Text); } if (Attributes.TryGet(out PropertyTooltipAttribute tooltipAttribute)) { CustomTooltip = ValueResolver.ResolveString(this, tooltipAttribute.Tooltip); } else if (Attributes.TryGet(out TooltipAttribute unityTooltipAttribute)) { CustomTooltip = new ConstantValueResolver(unityTooltipAttribute.tooltip); } } public Type OwnerType { get; } public Type FieldType { get; } public string Name { get; } public int Order { get; internal set; } public IReadOnlyList Attributes => _attributes; public bool IsReadOnly { get; } public bool IsArrayElement { get; } public Type ArrayElementType { get; } public bool IsArray { get; } [CanBeNull] public ValueResolver CustomLabel { get; } [CanBeNull] public ValueResolver CustomTooltip { get; } public IReadOnlyList HideProcessors => PopulateHideProcessor(); public IReadOnlyList DisableProcessors => PopulateDisableProcessors(); public IReadOnlyList Drawers => PopulateDrawers(); public IReadOnlyList Validators => PopulateValidators(); internal IReadOnlyList ExtensionErrors { get { PopulateHideProcessor(); PopulateDisableProcessors(); PopulateDrawers(); PopulateValidators(); return _extensionErrors; } } public List GetEditableAttributes() { return _attributes; } public bool TryGetMemberInfo(out MemberInfo memberInfo) { memberInfo = _memberInfo; return memberInfo != null; } public object GetValue(TriProperty property, int targetIndex) { var value = _valueGetter(property, targetIndex); if (value == null && !_skipNullValuesFix) { value = TriUnitySerializationUtilities.PopulateUnityDefaultValueForType(FieldType); if (value != null) { _valueSetter?.Invoke(property, targetIndex, value); } } return value; } public bool SetValue(TriProperty property, object value, int targetIndex, out object parentValue) { if (IsReadOnly) { Debug.LogError("Cannot set value for readonly property"); parentValue = default; return false; } parentValue = _valueSetter?.Invoke(property, targetIndex, value); return true; } public TriPropertyDefinition ArrayElementDefinition { get { if (_arrayElementDefinitionBackingField == null) { if (!IsArray) { throw new InvalidOperationException( $"Cannot get array element definition for non array property: {FieldType}"); } var elementGetter = new ValueGetterDelegate((self, targetIndex) => { var parentValue = (IList)self.Parent.GetValue(targetIndex); return parentValue[self.IndexInArray]; }); var elementSetter = new ValueSetterDelegate((self, targetIndex, value) => { var parentValue = (IList)self.Parent.GetValue(targetIndex); parentValue[self.IndexInArray] = value; return parentValue; }); _arrayElementDefinitionBackingField = new TriPropertyDefinition(_memberInfo, OwnerType, 0, "Element", ArrayElementType, elementGetter, elementSetter, _attributes, true); } return _arrayElementDefinitionBackingField; } } private IReadOnlyList PopulateHideProcessor() { if (_hideProcessorsBackingField != null) { return _hideProcessorsBackingField; } return _hideProcessorsBackingField = TriDrawersUtilities .CreateHideProcessorsFor(FieldType, Attributes) .Where(CanApplyExtensionOnSelf) .ToList(); } private IReadOnlyList PopulateDisableProcessors() { if (_disableProcessorsBackingField != null) { return _disableProcessorsBackingField; } return _disableProcessorsBackingField = TriDrawersUtilities .CreateDisableProcessorsFor(FieldType, Attributes) .Where(CanApplyExtensionOnSelf) .ToList(); } private IReadOnlyList PopulateValidators() { if (_validatorsBackingField != null) { return _validatorsBackingField; } return _validatorsBackingField = Enumerable.Empty() .Concat(TriDrawersUtilities.CreateValueValidatorsFor(FieldType)) .Concat(TriDrawersUtilities.CreateAttributeValidatorsFor(FieldType, Attributes)) .Where(CanApplyExtensionOnSelf) .ToList(); } private IReadOnlyList PopulateDrawers() { if (_drawersBackingField != null) { return _drawersBackingField; } return _drawersBackingField = Enumerable.Empty() .Concat(TriDrawersUtilities.CreateValueDrawersFor(FieldType)) .Concat(TriDrawersUtilities.CreateAttributeDrawersFor(FieldType, Attributes)) .Concat(new[] { new ValidatorsDrawer { Order = TriDrawerOrder.Validator, }, }) .Where(CanApplyExtensionOnSelf) .OrderBy(it => it.Order) .ToList(); } private static ValueGetterDelegate MakeGetter(FieldInfo fi) { return (self, targetIndex) => { var parentValue = self.Parent.GetValue(targetIndex); return fi.GetValue(parentValue); }; } private static ValueSetterDelegate MakeSetter(FieldInfo fi) { return (self, targetIndex, value) => { var parentValue = self.Parent.GetValue(targetIndex); fi.SetValue(parentValue, value); return parentValue; }; } private static ValueGetterDelegate MakeGetter(PropertyInfo pi) { var method = pi.GetMethod; return (self, targetIndex) => { var parentValue = self.Parent.GetValue(targetIndex); return method.Invoke(parentValue, null); }; } private static ValueSetterDelegate MakeSetter(PropertyInfo pi) { var method = pi.SetMethod; if (method == null) { return null; } return (self, targetIndex, value) => { var parentValue = self.Parent.GetValue(targetIndex); method.Invoke(parentValue, new[] { value, }); return parentValue; }; } private static ValueGetterDelegate MakeGetter(MethodInfo mi) { return (self, targetIndex) => mi; } private static ValueSetterDelegate MakeSetter(MethodInfo mi) { return (self, targetIndex, value) => { var parentValue = self.Parent.GetValue(targetIndex); return parentValue; }; } private bool CanApplyExtensionOnSelf(TriPropertyExtension propertyExtension) { if (propertyExtension.ApplyOnArrayElement.HasValue) { if (IsArrayElement && !propertyExtension.ApplyOnArrayElement.Value || IsArray && propertyExtension.ApplyOnArrayElement.Value) { return false; } } var result = propertyExtension.Initialize(this); if (result.IsError) { _extensionErrors.Add(result.ErrorMessage); } return result.ShouldApply; } public delegate object ValueGetterDelegate(TriProperty self, int targetIndex); public delegate object ValueSetterDelegate(TriProperty self, int targetIndex, object value); } } ================================================ FILE: VirtueSky/Inspector/Editor/TriPropertyDefinition.cs.meta ================================================ fileFormatVersion: 2 guid: 4feaa123e82e4c93846c94ebd3af253e timeCreated: 1638873323 ================================================ FILE: VirtueSky/Inspector/Editor/TriPropertyDisableProcessor.cs ================================================ using System; using JetBrains.Annotations; namespace VirtueSky.Inspector { public abstract class TriPropertyDisableProcessor : TriPropertyExtension { internal Attribute RawAttribute { get; set; } [PublicAPI] public abstract bool IsDisabled(TriProperty property); } public abstract class TriPropertyDisableProcessor : TriPropertyDisableProcessor where TAttribute : Attribute { [PublicAPI] public TAttribute Attribute => (TAttribute) RawAttribute; } } ================================================ FILE: VirtueSky/Inspector/Editor/TriPropertyDisableProcessor.cs.meta ================================================ fileFormatVersion: 2 guid: 2c01ea19c766412ba28df648a968abba timeCreated: 1641385496 ================================================ FILE: VirtueSky/Inspector/Editor/TriPropertyExtension.cs ================================================ using System; using JetBrains.Annotations; namespace VirtueSky.Inspector { public abstract class TriPropertyExtension { public bool? ApplyOnArrayElement { get; internal set; } [PublicAPI] public virtual TriExtensionInitializationResult Initialize(TriPropertyDefinition propertyDefinition) { return TriExtensionInitializationResult.Ok; } } public readonly struct TriExtensionInitializationResult { public TriExtensionInitializationResult(bool shouldApply, string errorMessage) { ShouldApply = shouldApply; ErrorMessage = errorMessage; } public bool ShouldApply { get; } public string ErrorMessage { get; } public bool IsError => ErrorMessage != null; [PublicAPI] public static TriExtensionInitializationResult Ok => new TriExtensionInitializationResult(true, null); [PublicAPI] public static TriExtensionInitializationResult Skip => new TriExtensionInitializationResult(false, null); [PublicAPI] public static TriExtensionInitializationResult Error([NotNull] string errorMessage) { if (errorMessage == null) { throw new ArgumentNullException(nameof(errorMessage)); } return new TriExtensionInitializationResult(false, errorMessage); } [PublicAPI] public static implicit operator TriExtensionInitializationResult(string errorMessage) { return Error(errorMessage); } } } ================================================ FILE: VirtueSky/Inspector/Editor/TriPropertyExtension.cs.meta ================================================ fileFormatVersion: 2 guid: 4da7122af7f84f1e8c0f2986e064e161 timeCreated: 1654255038 ================================================ FILE: VirtueSky/Inspector/Editor/TriPropertyHideProcessor.cs ================================================ using System; using JetBrains.Annotations; namespace VirtueSky.Inspector { public abstract class TriPropertyHideProcessor : TriPropertyExtension { internal Attribute RawAttribute { get; set; } [PublicAPI] public abstract bool IsHidden(TriProperty property); } public abstract class TriPropertyHideProcessor : TriPropertyHideProcessor where TAttribute : Attribute { [PublicAPI] public TAttribute Attribute => (TAttribute) RawAttribute; } } ================================================ FILE: VirtueSky/Inspector/Editor/TriPropertyHideProcessor.cs.meta ================================================ fileFormatVersion: 2 guid: de11bb184a7d4c7f9c6a4f2a75756278 timeCreated: 1641384283 ================================================ FILE: VirtueSky/Inspector/Editor/TriPropertyOverrideContext.cs ================================================ using System; using UnityEngine; namespace VirtueSky.Inspector { public abstract class TriPropertyOverrideContext { private static TriPropertyOverrideContext Override { get; set; } public static TriPropertyOverrideContext Current { get; private set; } public abstract bool TryGetDisplayName(TriProperty property, out GUIContent displayName); public static EnterPropertyScope BeginProperty() { return new EnterPropertyScope().Init(); } public static OverrideScope BeginOverride(TriPropertyOverrideContext overrideContext) { return new OverrideScope(overrideContext); } public struct EnterPropertyScope { private TriPropertyOverrideContext _previousContext; public EnterPropertyScope Init() { _previousContext = Current; Current = Override; Override = null; return this; } public void EndProperty() { Override = Current; Current = _previousContext; } } public readonly struct OverrideScope : IDisposable { public OverrideScope(TriPropertyOverrideContext context) { if (Override != null) { Debug.LogError($"TriPropertyContext already overriden with {Override.GetType()}"); } Override = context; } public void Dispose() { Override = null; } } } } ================================================ FILE: VirtueSky/Inspector/Editor/TriPropertyOverrideContext.cs.meta ================================================ fileFormatVersion: 2 guid: 009410b38db449a1a47369c87a015b0d timeCreated: 1643555608 ================================================ FILE: VirtueSky/Inspector/Editor/TriPropertyTree.cs ================================================ using System; using VirtueSky.Inspector.Elements; using UnityEditor; using UnityEngine; using UnityEngine.Profiling; namespace VirtueSky.Inspector { public abstract class TriPropertyTree : IDisposable { private TriPropertyElement _rootPropertyElement; private Rect _cachedOuterRect = new Rect(0, 0, 0, 0); public TriPropertyDefinition RootPropertyDefinition { get; protected set; } public TriProperty RootProperty { get; protected set; } public Type TargetObjectType { get; protected set; } public int TargetsCount { get; protected set; } public bool TargetIsPersistent { get; protected set; } public bool ValidationRequired { get; private set; } = true; public bool RepaintRequired { get; private set; } = true; public int RepaintFrame { get; private set; } = 0; public virtual void Dispose() { if (_rootPropertyElement != null && _rootPropertyElement.IsAttached) { _rootPropertyElement.DetachInternal(); } } public virtual void Update(bool forceUpdate = false) { RepaintFrame++; } public virtual bool ApplyChanges() { return false; } public void RunValidationIfRequired() { if (!ValidationRequired) { return; } RunValidation(); } public void RunValidation() { ValidationRequired = false; Profiler.BeginSample("TriInspector.RunValidation"); RootProperty.RunValidation(); Profiler.EndSample(); RequestRepaint(); } public virtual void Draw() { RepaintRequired = false; if (_rootPropertyElement == null) { _rootPropertyElement = new TriPropertyElement(RootProperty, new TriPropertyElement.Props { forceInline = !RootProperty.TryGetMemberInfo(out _), }); _rootPropertyElement.AttachInternal(); } Profiler.BeginSample("TriInspector.UpdateRootPropertyElement"); _rootPropertyElement.Update(); Profiler.EndSample(); var rectOuter = GUILayoutUtility.GetRect(0, 9999, 0, 0); _cachedOuterRect = Event.current.type == EventType.Layout ? _cachedOuterRect : rectOuter; var rect = new Rect(_cachedOuterRect); rect = EditorGUI.IndentedRect(rect); rect.height = _rootPropertyElement.GetHeight(rect.width); var oldIndent = EditorGUI.indentLevel; EditorGUI.indentLevel = 0; GUILayoutUtility.GetRect(_cachedOuterRect.width, rect.height); Profiler.BeginSample("TriInspector.DrawRootPropertyElement"); _rootPropertyElement.OnGUI(rect); Profiler.EndSample(); EditorGUI.indentLevel = oldIndent; } public void EnumerateValidationResults(Action call) { RootProperty.EnumerateValidationResults(call); } public void RequestRepaint() { RepaintRequired = true; } public void RequestValidation() { ValidationRequired = true; RequestRepaint(); } public abstract void ForceCreateUndoGroup(); } } ================================================ FILE: VirtueSky/Inspector/Editor/TriPropertyTree.cs.meta ================================================ fileFormatVersion: 2 guid: 9bb1d443163b4a26908eb26ba297c1d6 timeCreated: 1653126491 ================================================ FILE: VirtueSky/Inspector/Editor/TriPropertyTreeForSerializedObject.cs ================================================ using System; using System.Collections.Generic; using JetBrains.Annotations; using UnityEditor; namespace VirtueSky.Inspector { public sealed class TriPropertyTreeForSerializedObject : TriPropertyTree { private readonly SerializedObject _serializedObject; private readonly SerializedProperty _scriptProperty; public TriPropertyTreeForSerializedObject([NotNull] SerializedObject serializedObject) { _serializedObject = serializedObject ?? throw new ArgumentNullException(nameof(serializedObject)); _scriptProperty = serializedObject.FindProperty("m_Script"); TargetObjectType = _serializedObject.targetObject.GetType(); TargetsCount = _serializedObject.targetObjects.Length; TargetIsPersistent = _serializedObject.targetObject is var targetObject && targetObject != null && EditorUtility.IsPersistent(targetObject); RootPropertyDefinition = new TriPropertyDefinition( memberInfo: null, ownerType: null, order: -1, fieldName: "ROOT", fieldType: TargetObjectType, valueGetter: (self, targetIndex) => _serializedObject.targetObjects[targetIndex], valueSetter: (self, targetIndex, value) => _serializedObject.targetObjects[targetIndex], attributes: new List(), isArrayElement: false); RootProperty = new TriProperty(this, null, RootPropertyDefinition, serializedObject); RootProperty.ValueChanged += OnPropertyChanged; RootProperty.ChildValueChanged += OnPropertyChanged; } public override void Dispose() { RootProperty.ChildValueChanged -= OnPropertyChanged; RootProperty.ValueChanged -= OnPropertyChanged; base.Dispose(); } public override void Update(bool forceUpdate = false) { if (forceUpdate) { _serializedObject.SetIsDifferentCacheDirty(); _serializedObject.Update(); } base.Update(forceUpdate); } public override void Draw() { DrawMonoScriptProperty(); base.Draw(); } public override bool ApplyChanges() { var changed = base.ApplyChanges(); changed |= _serializedObject.ApplyModifiedProperties(); return changed; } public override void ForceCreateUndoGroup() { Undo.RegisterCompleteObjectUndo(_serializedObject.targetObjects, "Inspector"); Undo.FlushUndoRecordObjects(); } private void OnPropertyChanged(TriProperty changedProperty) { foreach (var targetObject in _serializedObject.targetObjects) { EditorUtility.SetDirty(targetObject); } RequestValidation(); RequestRepaint(); } private void DrawMonoScriptProperty() { if (RootProperty.TryGetAttribute(out HideMonoScriptAttribute _)) { return; } EditorGUI.BeginDisabledGroup(true); var scriptRect = EditorGUILayout.GetControlRect(true); scriptRect.xMin += 3; EditorGUI.PropertyField(scriptRect, _scriptProperty); EditorGUI.EndDisabledGroup(); } } } ================================================ FILE: VirtueSky/Inspector/Editor/TriPropertyTreeForSerializedObject.cs.meta ================================================ fileFormatVersion: 2 guid: 468b264c3e164c0681760c3d98451466 timeCreated: 1638857169 ================================================ FILE: VirtueSky/Inspector/Editor/TriTypeDefinition.cs ================================================ using System; using System.Collections.Generic; using VirtueSky.Inspector.Utilities; namespace VirtueSky.Inspector { public class TriTypeDefinition { private static readonly Dictionary Cache = new Dictionary(); private TriTypeDefinition(IReadOnlyList properties) { Properties = properties; } public IReadOnlyList Properties { get; } public static TriTypeDefinition GetCached(Type type) { if (Cache.TryGetValue(type, out var definition)) { return definition; } var processors = TriDrawersUtilities.AllTypeProcessors; var properties = new List(); foreach (var processor in processors) { processor.ProcessType(type, properties); } return Cache[type] = new TriTypeDefinition(properties); } } } ================================================ FILE: VirtueSky/Inspector/Editor/TriTypeDefinition.cs.meta ================================================ fileFormatVersion: 2 guid: 034ca4c8b571472fb71db422a48cfe07 timeCreated: 1638870763 ================================================ FILE: VirtueSky/Inspector/Editor/TriTypeProcessor.cs ================================================ using System; using System.Collections.Generic; namespace VirtueSky.Inspector { public abstract class TriTypeProcessor { public abstract void ProcessType(Type type, List properties); } } ================================================ FILE: VirtueSky/Inspector/Editor/TriTypeProcessor.cs.meta ================================================ fileFormatVersion: 2 guid: 0a7c26cf735e465d8373066f830cf5c4 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Inspector/Editor/TriValidator.cs ================================================ using System; using JetBrains.Annotations; namespace VirtueSky.Inspector { public abstract class TriValidator : TriPropertyExtension { [PublicAPI] public abstract TriValidationResult Validate(TriProperty property); } public abstract class TriAttributeValidator : TriValidator { internal Attribute RawAttribute { get; set; } } public abstract class TriAttributeValidator : TriAttributeValidator where TAttribute : Attribute { [PublicAPI] public TAttribute Attribute => (TAttribute) RawAttribute; } public abstract class TriValueValidator : TriValidator { } public abstract class TriValueValidator : TriValueValidator { public sealed override TriValidationResult Validate(TriProperty property) { return Validate(new TriValue(property)); } [PublicAPI] public abstract TriValidationResult Validate(TriValue propertyValue); } } ================================================ FILE: VirtueSky/Inspector/Editor/TriValidator.cs.meta ================================================ fileFormatVersion: 2 guid: b90ba6bdef614e9aa246f371506ea113 timeCreated: 1642260754 ================================================ FILE: VirtueSky/Inspector/Editor/TriValue.cs ================================================ using System; using JetBrains.Annotations; namespace VirtueSky.Inspector { public struct TriValue { internal TriValue(TriProperty property) { Property = property; } public TriProperty Property { get; } [Obsolete("Use SmartValue instead", true)] public T Value { get => (T) Property.Value; set => Property.SetValue(value); } [PublicAPI] public T SmartValue { get => (T) Property.Value; set { if (Property.Comparer.Equals(Property.Value, value)) { return; } Property.SetValue(value); } } [PublicAPI] public void SetValue(T value) { Property.SetValue(value); } } } ================================================ FILE: VirtueSky/Inspector/Editor/TriValue.cs.meta ================================================ fileFormatVersion: 2 guid: a925dd69982048009ab567f0b75ec326 timeCreated: 1639381003 ================================================ FILE: VirtueSky/Inspector/Editor/TriValueDrawer.cs ================================================ using JetBrains.Annotations; using UnityEngine; namespace VirtueSky.Inspector { public abstract class TriValueDrawer : TriCustomDrawer { } public abstract class TriValueDrawer : TriValueDrawer { public sealed override TriElement CreateElementInternal(TriProperty property, TriElement next) { return CreateElement(new TriValue(property), next); } [PublicAPI] public virtual TriElement CreateElement(TriValue propertyValue, TriElement next) { return new DefaultValueDrawerElement(this, propertyValue, next); } [PublicAPI] public virtual float GetHeight(float width, TriValue propertyValue, TriElement next) { return next.GetHeight(width); } [PublicAPI] public virtual void OnGUI(Rect position, TriValue propertyValue, TriElement next) { next.OnGUI(position); } internal class DefaultValueDrawerElement : TriElement { private readonly TriValueDrawer _drawer; private readonly TriElement _next; private readonly TriValue _propertyValue; public DefaultValueDrawerElement(TriValueDrawer drawer, TriValue propertyValue, TriElement next) { _drawer = drawer; _propertyValue = propertyValue; _next = next; AddChild(next); } public override float GetHeight(float width) { return _drawer.GetHeight(width, _propertyValue, _next); } public override void OnGUI(Rect position) { _drawer.OnGUI(position, _propertyValue, _next); } } } } ================================================ FILE: VirtueSky/Inspector/Editor/TriValueDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: dfd7988d91ca4f879f888735018e9116 timeCreated: 1639381337 ================================================ FILE: VirtueSky/Inspector/Editor/TypeProcessors/TriGroupNextTypeProcessor.cs ================================================ using System; using System.Collections.Generic; using VirtueSky.Inspector; using VirtueSky.Inspector.TypeProcessors; using VirtueSky.Inspector.Utilities; [assembly: RegisterTriTypeProcessor(typeof(TriGroupNextTypeProcessor), 11000)] namespace VirtueSky.Inspector.TypeProcessors { public class TriGroupNextTypeProcessor : TriTypeProcessor { public override void ProcessType(Type type, List properties) { TriPropertyDefinition groupProperty = null; GroupAttribute groupAttribute = null; TabAttribute tabAttribute = null; foreach (var property in properties) { if (groupProperty != null) { if (groupProperty.OwnerType != property.OwnerType || groupProperty.Order + 1000 < property.Order) { groupProperty = null; groupAttribute = null; tabAttribute = null; } } if (property.Attributes.TryGet(out GroupNextAttribute groupNextAttribute)) { groupProperty = property; groupAttribute = groupNextAttribute.Path != null ? new GroupAttribute(groupNextAttribute.Path) : null; property.Attributes.TryGet(out tabAttribute); } if (groupAttribute != null && !property.Attributes.TryGet(out GroupAttribute _)) { property.GetEditableAttributes().Add(groupAttribute); } if (tabAttribute != null && !property.Attributes.TryGet(out TabAttribute _)) { property.GetEditableAttributes().Add(tabAttribute); } } } } } ================================================ FILE: VirtueSky/Inspector/Editor/TypeProcessors/TriGroupNextTypeProcessor.cs.meta ================================================ fileFormatVersion: 2 guid: ef78c1a907f144a4bedc9cf2433d2526 timeCreated: 1660802896 ================================================ FILE: VirtueSky/Inspector/Editor/TypeProcessors/TriRectOffsetTypeProcessor.cs ================================================ using System; using System.Collections.Generic; using System.Reflection; using VirtueSky.Inspector; using VirtueSky.Inspector.TypeProcessors; using UnityEngine; [assembly: RegisterTriTypeProcessor(typeof(TriRectOffsetTypeProcessor), 1)] namespace VirtueSky.Inspector.TypeProcessors { public class TriRectOffsetTypeProcessor : TriTypeProcessor { private static readonly string[] DrawnProperties = new[] { "left", "right", "top", "bottom", }; public override void ProcessType(Type type, List properties) { if (type != typeof(RectOffset)) { return; } for (var i = 0; i < DrawnProperties.Length; i++) { var propertyName = DrawnProperties[i]; var propertyInfo = type.GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public); var propertyDef = TriPropertyDefinition.CreateForPropertyInfo(i, propertyInfo); properties.Add(propertyDef); } } } } ================================================ FILE: VirtueSky/Inspector/Editor/TypeProcessors/TriRectOffsetTypeProcessor.cs.meta ================================================ fileFormatVersion: 2 guid: 83fc30fabc614cb7a2501332802a2094 timeCreated: 1676534091 ================================================ FILE: VirtueSky/Inspector/Editor/TypeProcessors/TriRegisterButtonsTypeProcessor.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using VirtueSky.Inspector; using VirtueSky.Inspector.TypeProcessors; using VirtueSky.Inspector.Utilities; [assembly: RegisterTriTypeProcessor(typeof(TriRegisterButtonsTypeProcessor), 3)] namespace VirtueSky.Inspector.TypeProcessors { public class TriRegisterButtonsTypeProcessor : TriTypeProcessor { public override void ProcessType(Type type, List properties) { const int methodsOffset = 20001; properties.AddRange(TriReflectionUtilities .GetAllInstanceMethodsInDeclarationOrder(type) .Where(IsSerialized) .Select((it, ind) => TriPropertyDefinition.CreateForMethodInfo(ind + methodsOffset, it))); } private static bool IsSerialized(MethodInfo methodInfo) { return methodInfo.GetCustomAttribute(false) != null; } } } ================================================ FILE: VirtueSky/Inspector/Editor/TypeProcessors/TriRegisterButtonsTypeProcessor.cs.meta ================================================ fileFormatVersion: 2 guid: abe3b6771e754b2da1b3d226784ad02e timeCreated: 1660755911 ================================================ FILE: VirtueSky/Inspector/Editor/TypeProcessors/TriRegisterShownByTriFieldsTypeProcessor.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using VirtueSky.Inspector; using VirtueSky.Inspector.TypeProcessors; using VirtueSky.Inspector.Utilities; [assembly: RegisterTriTypeProcessor(typeof(TriRegisterShownByTriFieldsTypeProcessor), 1)] namespace VirtueSky.Inspector.TypeProcessors { public class TriRegisterShownByTriFieldsTypeProcessor : TriTypeProcessor { public override void ProcessType(Type type, List properties) { const int fieldsOffset = 5001; properties.AddRange(TriReflectionUtilities .GetAllInstanceFieldsInDeclarationOrder(type) .Where(IsSerialized) .Select((it, ind) => TriPropertyDefinition.CreateForFieldInfo(ind + fieldsOffset, it))); } private static bool IsSerialized(FieldInfo fieldInfo) { return fieldInfo.GetCustomAttribute(false) != null && TriUnitySerializationUtilities.IsSerializableByUnity(fieldInfo) == false; } } } ================================================ FILE: VirtueSky/Inspector/Editor/TypeProcessors/TriRegisterShownByTriFieldsTypeProcessor.cs.meta ================================================ fileFormatVersion: 2 guid: d5a485127f534bee963f620f86287c34 timeCreated: 1670601276 ================================================ FILE: VirtueSky/Inspector/Editor/TypeProcessors/TriRegisterShownByTriPropertiesTypeProcessor.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using VirtueSky.Inspector; using VirtueSky.Inspector.TypeProcessors; using VirtueSky.Inspector.Utilities; [assembly: RegisterTriTypeProcessor(typeof(TriRegisterShownByTriPropertiesTypeProcessor), 1)] namespace VirtueSky.Inspector.TypeProcessors { public class TriRegisterShownByTriPropertiesTypeProcessor : TriTypeProcessor { public override void ProcessType(Type type, List properties) { const int propertiesOffset = 10001; properties.AddRange(TriReflectionUtilities .GetAllInstancePropertiesInDeclarationOrder(type) .Where(IsSerialized) .Select((it, ind) => TriPropertyDefinition.CreateForPropertyInfo(ind + propertiesOffset, it))); } private static bool IsSerialized(PropertyInfo propertyInfo) { return propertyInfo.GetCustomAttribute(false) != null; } } } ================================================ FILE: VirtueSky/Inspector/Editor/TypeProcessors/TriRegisterShownByTriPropertiesTypeProcessor.cs.meta ================================================ fileFormatVersion: 2 guid: c57e9a6e1c4e46558fb3c43ffb404a57 timeCreated: 1660755901 ================================================ FILE: VirtueSky/Inspector/Editor/TypeProcessors/TriRegisterUnitySerializedFieldsTypeProcessor.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using VirtueSky.Inspector; using VirtueSky.Inspector.TypeProcessors; using VirtueSky.Inspector.Utilities; [assembly: RegisterTriTypeProcessor(typeof(TriRegisterUnitySerializedFieldsTypeProcessor), 0)] namespace VirtueSky.Inspector.TypeProcessors { public class TriRegisterUnitySerializedFieldsTypeProcessor : TriTypeProcessor { public override void ProcessType(Type type, List properties) { const int fieldsOffset = 1; properties.AddRange(TriReflectionUtilities .GetAllInstanceFieldsInDeclarationOrder(type) .Where(IsSerialized) .Select((it, ind) => TriPropertyDefinition.CreateForFieldInfo(ind + fieldsOffset, it))); } private static bool IsSerialized(FieldInfo fieldInfo) { return TriUnitySerializationUtilities.IsSerializableByUnity(fieldInfo); } } } ================================================ FILE: VirtueSky/Inspector/Editor/TypeProcessors/TriRegisterUnitySerializedFieldsTypeProcessor.cs.meta ================================================ fileFormatVersion: 2 guid: 5a19f117ac85440cb8896b8b90a9f17a timeCreated: 1660755421 ================================================ FILE: VirtueSky/Inspector/Editor/TypeProcessors/TriSortPropertiesTypeProcessor.cs ================================================ using System; using System.Collections.Generic; using VirtueSky.Inspector; using VirtueSky.Inspector.TypeProcessors; using VirtueSky.Inspector.Utilities; [assembly: RegisterTriTypeProcessor(typeof(TriSortPropertiesTypeProcessor), 10000)] namespace VirtueSky.Inspector.TypeProcessors { public class TriSortPropertiesTypeProcessor : TriTypeProcessor { public override void ProcessType(Type type, List properties) { foreach (var propertyDefinition in properties) { if (propertyDefinition.Attributes.TryGet(out PropertyOrderAttribute orderAttribute)) { propertyDefinition.Order = orderAttribute.Order; } } properties.Sort(PropertyOrderComparer.Instance); } private class PropertyOrderComparer : IComparer { public static readonly PropertyOrderComparer Instance = new PropertyOrderComparer(); public int Compare(TriPropertyDefinition x, TriPropertyDefinition y) { return x.Order.CompareTo(y.Order); } } } } ================================================ FILE: VirtueSky/Inspector/Editor/TypeProcessors/TriSortPropertiesTypeProcessor.cs.meta ================================================ fileFormatVersion: 2 guid: 900dee18b5e245198d1891d10d0a954b timeCreated: 1660756062 ================================================ FILE: VirtueSky/Inspector/Editor/TypeProcessors.meta ================================================ fileFormatVersion: 2 guid: 52aec2fc04054420970349733f05237b folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Inspector/Editor/Utilities/TriAttributeUtilities.cs ================================================ using System; using System.Collections.Generic; namespace VirtueSky.Inspector.Utilities { internal static class TriAttributeUtilities { public static bool TryGet(this IReadOnlyList attributes, out T it) where T : Attribute { foreach (var attribute in attributes) { if (attribute is T typeAttribute) { it = typeAttribute; return true; } } it = null; return false; } } } ================================================ FILE: VirtueSky/Inspector/Editor/Utilities/TriAttributeUtilities.cs.meta ================================================ fileFormatVersion: 2 guid: ff3eb732102046b0b36e76f9d17cab4e timeCreated: 1638876778 ================================================ FILE: VirtueSky/Inspector/Editor/Utilities/TriDrawersUtilities.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using VirtueSky.Inspector.Elements; using UnityEngine; namespace VirtueSky.Inspector.Utilities { internal class TriDrawersUtilities { private static readonly GenericTypeMatcher GroupDrawerMatcher = typeof(TriGroupDrawer<>); private static readonly GenericTypeMatcher ValueDrawerMatcher = typeof(TriValueDrawer<>); private static readonly GenericTypeMatcher AttributeDrawerMatcher = typeof(TriAttributeDrawer<>); private static readonly GenericTypeMatcher ValueValidatorMatcher = typeof(TriValueValidator<>); private static readonly GenericTypeMatcher AttributeValidatorMatcher = typeof(TriAttributeValidator<>); private static readonly GenericTypeMatcher HideProcessorMatcher = typeof(TriPropertyHideProcessor<>); private static readonly GenericTypeMatcher DisableProcessorMatcher = typeof(TriPropertyDisableProcessor<>); private static IDictionary _allGroupDrawersCacheBackingField; private static IReadOnlyList _allAttributeDrawerTypesBackingField; private static IReadOnlyList _allValueDrawerTypesBackingField; private static IReadOnlyList _allAttributeValidatorTypesBackingField; private static IReadOnlyList _allValueValidatorTypesBackingField; private static IReadOnlyList _allHideProcessorTypesBackingField; private static IReadOnlyList _allDisableProcessorTypesBackingField; private static IReadOnlyList _allTypeProcessorBackingField; private static IDictionary AllGroupDrawersCache { get { if (_allGroupDrawersCacheBackingField == null) { _allGroupDrawersCacheBackingField = ( from asm in TriReflectionUtilities.Assemblies from attr in asm.GetCustomAttributes() let groupAttributeType = GroupDrawerMatcher.MatchOut(attr.DrawerType, out var t) ? t : null where groupAttributeType != null select new KeyValuePair(groupAttributeType, attr) ).ToDictionary( it => it.Key, it => (TriGroupDrawer) Activator.CreateInstance(it.Value.DrawerType)); } return _allGroupDrawersCacheBackingField; } } public static IReadOnlyList AllTypeProcessors { get { if (_allTypeProcessorBackingField == null) { _allTypeProcessorBackingField = ( from asm in TriReflectionUtilities.Assemblies from attr in asm.GetCustomAttributes() orderby attr.Order select (TriTypeProcessor) Activator.CreateInstance(attr.ProcessorType) ).ToList(); } return _allTypeProcessorBackingField; } } public static IReadOnlyList AllValueDrawerTypes { get { if (_allValueDrawerTypesBackingField == null) { _allValueDrawerTypesBackingField = ( from asm in TriReflectionUtilities.Assemblies from attr in asm.GetCustomAttributes() where ValueDrawerMatcher.Match(attr.DrawerType) select attr ).ToList(); } return _allValueDrawerTypesBackingField; } } public static IReadOnlyList AllAttributeDrawerTypes { get { if (_allAttributeDrawerTypesBackingField == null) { _allAttributeDrawerTypesBackingField = ( from asm in TriReflectionUtilities.Assemblies from attr in asm.GetCustomAttributes() where AttributeDrawerMatcher.Match(attr.DrawerType) select attr ).ToList(); } return _allAttributeDrawerTypesBackingField; } } public static IReadOnlyList AllValueValidatorTypes { get { if (_allValueValidatorTypesBackingField == null) { _allValueValidatorTypesBackingField = ( from asm in TriReflectionUtilities.Assemblies from attr in asm.GetCustomAttributes() where ValueValidatorMatcher.Match(attr.ValidatorType) select attr ).ToList(); } return _allValueValidatorTypesBackingField; } } public static IReadOnlyList AllAttributeValidatorTypes { get { if (_allAttributeValidatorTypesBackingField == null) { _allAttributeValidatorTypesBackingField = ( from asm in TriReflectionUtilities.Assemblies from attr in asm.GetCustomAttributes() where AttributeValidatorMatcher.Match(attr.ValidatorType) select attr ).ToList(); } return _allAttributeValidatorTypesBackingField; } } public static IReadOnlyList AllHideProcessors { get { if (_allHideProcessorTypesBackingField == null) { _allHideProcessorTypesBackingField = ( from asm in TriReflectionUtilities.Assemblies from attr in asm.GetCustomAttributes() where HideProcessorMatcher.Match(attr.ProcessorType) select attr ).ToList(); } return _allHideProcessorTypesBackingField; } } public static IReadOnlyList AllDisableProcessors { get { if (_allDisableProcessorTypesBackingField == null) { _allDisableProcessorTypesBackingField = ( from asm in TriReflectionUtilities.Assemblies from attr in asm.GetCustomAttributes() where DisableProcessorMatcher.Match(attr.ProcessorType) select attr ).ToList(); } return _allDisableProcessorTypesBackingField; } } public static TriPropertyCollectionBaseElement TryCreateGroupElementFor(DeclareGroupBaseAttribute attribute) { if (!AllGroupDrawersCache.TryGetValue(attribute.GetType(), out var attr)) { return null; } return attr.CreateElementInternal(attribute); } public static IEnumerable CreateValueDrawersFor(Type valueType) { return from drawer in AllValueDrawerTypes where ValueDrawerMatcher.Match(drawer.DrawerType, valueType) select CreateInstance(drawer.DrawerType, valueType, it => { it.ApplyOnArrayElement = drawer.ApplyOnArrayElement; it.Order = drawer.Order; }); } public static IEnumerable CreateAttributeDrawersFor( Type valueType, IReadOnlyList attributes) { return from attribute in attributes from drawer in AllAttributeDrawerTypes where AttributeDrawerMatcher.Match(drawer.DrawerType, attribute.GetType()) select CreateInstance(drawer.DrawerType, valueType, it => { it.ApplyOnArrayElement = drawer.ApplyOnArrayElement; it.Order = drawer.Order; it.RawAttribute = attribute; }); } public static IEnumerable CreateValueValidatorsFor(Type valueType) { return from validator in AllValueValidatorTypes where ValueValidatorMatcher.Match(validator.ValidatorType, valueType) select CreateInstance(validator.ValidatorType, valueType, it => { // it.ApplyOnArrayElement = validator.ApplyOnArrayElement; }); } public static IEnumerable CreateAttributeValidatorsFor( Type valueType, IReadOnlyList attributes) { return from attribute in attributes from validator in AllAttributeValidatorTypes where AttributeValidatorMatcher.Match(validator.ValidatorType, attribute.GetType()) select CreateInstance(validator.ValidatorType, valueType, it => { it.ApplyOnArrayElement = validator.ApplyOnArrayElement; it.RawAttribute = attribute; }); } public static IEnumerable CreateHideProcessorsFor( Type valueType, IReadOnlyList attributes) { return from attribute in attributes from processor in AllHideProcessors where HideProcessorMatcher.Match(processor.ProcessorType, attribute.GetType()) select CreateInstance( processor.ProcessorType, valueType, it => { it.ApplyOnArrayElement = processor.ApplyOnArrayElement; it.RawAttribute = attribute; }); } public static IEnumerable CreateDisableProcessorsFor( Type valueType, IReadOnlyList attributes) { return from attribute in attributes from processor in AllDisableProcessors where DisableProcessorMatcher.Match(processor.ProcessorType, attribute.GetType()) select CreateInstance( processor.ProcessorType, valueType, it => { it.ApplyOnArrayElement = processor.ApplyOnArrayElement; it.RawAttribute = attribute; }); } private static T CreateInstance(Type type, Type argType, Action setup) { if (type.IsGenericType) { type = type.MakeGenericType(argType); } var instance = (T) Activator.CreateInstance(type); setup(instance); return instance; } private class GenericTypeMatcher { private readonly Dictionary _cache = new Dictionary(); private readonly Type _expectedGenericType; private GenericTypeMatcher(Type expectedGenericType) { _expectedGenericType = expectedGenericType; } public static implicit operator GenericTypeMatcher(Type expectedGenericType) { return new GenericTypeMatcher(expectedGenericType); } public bool Match(Type type, Type targetType) { return MatchOut(type, out var constraint) && constraint.IsAssignableFrom(targetType); } public bool Match(Type type) { return MatchOut(type, out _); } public bool MatchOut(Type type, out Type targetType) { if (_cache.TryGetValue(type, out var cachedResult)) { targetType = cachedResult.Item2; return cachedResult.Item1; } var succeed = MatchInternal(type, out targetType); _cache[type] = (succeed, targetType); return succeed; } private bool MatchInternal(Type type, out Type targetType) { targetType = null; if (type.IsAbstract) { Debug.LogError($"{type.Name} must be non abstract"); return false; } if (type.GetConstructor(Type.EmptyTypes) == null) { Debug.LogError($"{type.Name} must have a parameterless constructor"); return false; } Type genericArgConstraints = null; if (type.IsGenericType) { var genericArg = type.GetGenericArguments().SingleOrDefault(); if (genericArg == null || genericArg.GenericParameterAttributes != GenericParameterAttributes.None) { Debug.LogError( $"{type.Name} must contains only one generic arg with simple constant e.g. "); return false; } genericArgConstraints = genericArg.GetGenericParameterConstraints().SingleOrDefault(); } var drawerType = type.BaseType; while (drawerType != null) { if (drawerType.IsGenericType && drawerType.GetGenericTypeDefinition() == _expectedGenericType) { targetType = drawerType.GetGenericArguments()[0]; if (targetType.IsGenericParameter) { if (genericArgConstraints == null) { Debug.LogError( $"{type.Name} must contains only one generic arg with simple constant e.g. "); return false; } targetType = genericArgConstraints; } return true; } drawerType = drawerType.BaseType; } Debug.LogError($"{type.Name} must implement {_expectedGenericType}"); return false; } } } } ================================================ FILE: VirtueSky/Inspector/Editor/Utilities/TriDrawersUtilities.cs.meta ================================================ fileFormatVersion: 2 guid: fbb9d9e8efd64dedb3b04ab3f90317f7 timeCreated: 1638886023 ================================================ FILE: VirtueSky/Inspector/Editor/Utilities/TriEditorGUI.cs ================================================ using UnityEditor; using UnityEngine; namespace VirtueSky.Inspector.Utilities { public static class TriEditorGUI { public static void Foldout(Rect rect, TriProperty property) { var content = property.DisplayNameContent; if (property.TryGetSerializedProperty(out var serializedProperty)) { EditorGUI.BeginProperty(rect, content, serializedProperty); property.IsExpanded = EditorGUI.Foldout(rect, property.IsExpanded, content, true); EditorGUI.EndProperty(); } else { property.IsExpanded = EditorGUI.Foldout(rect, property.IsExpanded, content, true); } } public static void DrawBox(Rect position, GUIStyle style, bool isHover = false, bool isActive = false, bool on = false, bool hasKeyboardFocus = false) { if (Event.current.type == EventType.Repaint) { style.Draw(position, GUIContent.none, isHover, isActive, on, hasKeyboardFocus); } } } } ================================================ FILE: VirtueSky/Inspector/Editor/Utilities/TriEditorGUI.cs.meta ================================================ fileFormatVersion: 2 guid: 59bc827ebe19464ea936ff5cf8ae1b7f timeCreated: 1638864333 ================================================ FILE: VirtueSky/Inspector/Editor/Utilities/TriEqualityComparer.cs ================================================ using System; using System.Collections; using System.Collections.Generic; using System.Reflection; namespace VirtueSky.Inspector.Utilities { public static class TriEqualityComparer { private static readonly Dictionary Cache = new Dictionary(); public static IEqualityComparer Of(Type type) { if (!Cache.TryGetValue(type, out var comparer)) { Cache[type] = comparer = CreateDefaultEqualityComparer(type); } return comparer; } private static IEqualityComparer CreateDefaultEqualityComparer(Type type) { var comparerType = typeof(EqualityComparer<>).MakeGenericType(type); var comparerProperty = comparerType.GetProperty("Default", BindingFlags.Static | BindingFlags.Public); var comparer = (IEqualityComparer) comparerProperty?.GetValue(null); if (comparer == null) { throw new InvalidOperationException($"Failed to create default comparer for type {type}"); } return comparer; } } } ================================================ FILE: VirtueSky/Inspector/Editor/Utilities/TriEqualityComparer.cs.meta ================================================ fileFormatVersion: 2 guid: 47b9c566490541bcbfcf7fc93bf7bdea MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Inspector/Editor/Utilities/TriGuiHelper.cs ================================================ using System; using System.Collections.Generic; using UnityEditor; using UnityEngine; using Object = UnityEngine.Object; namespace VirtueSky.Inspector.Utilities { public static class TriGuiHelper { private static readonly GUIContent TempContentShared = new GUIContent(); private static readonly Stack TargetObjects = new Stack(); public static GUIContent TempContent(string text) { TempContentShared.text = text; return TempContentShared; } internal static bool IsAnyEditorPushed() { return TargetObjects.Count > 0; } internal static bool IsEditorTargetPushed(Object obj) { foreach (var targetObject in TargetObjects) { if (targetObject == obj) { return true; } } return false; } internal static EditorScope PushEditorTarget(Object obj) { return new EditorScope(obj); } public static LabelWidthScope PushLabelWidth(float labelWidth) { return new LabelWidthScope(labelWidth); } public static IndentedRectScope PushIndentedRect(Rect source, int indentLevel) { return new IndentedRectScope(source, indentLevel); } public static GuiColorScope PushColor(Color color) { return new GuiColorScope(color); } public readonly struct EditorScope : IDisposable { public EditorScope(Object obj) { TargetObjects.Push(obj); } public void Dispose() { TargetObjects.Pop(); } } public readonly struct LabelWidthScope : IDisposable { private readonly float _oldLabelWidth; public LabelWidthScope(float labelWidth) { _oldLabelWidth = EditorGUIUtility.labelWidth; if (labelWidth > 0) { EditorGUIUtility.labelWidth = labelWidth; } } public void Dispose() { EditorGUIUtility.labelWidth = _oldLabelWidth; } } public readonly struct IndentedRectScope : IDisposable { private readonly float _indent; public Rect IndentedRect { get; } public IndentedRectScope(Rect source, int indentLevel) { _indent = indentLevel * 15; IndentedRect = new Rect(source.x + _indent, source.y, source.width - _indent, source.height); EditorGUIUtility.labelWidth -= _indent; } public void Dispose() { EditorGUIUtility.labelWidth += _indent; } } public readonly struct GuiColorScope : IDisposable { private readonly Color _oldColor; public GuiColorScope(Color color) { _oldColor = GUI.color; GUI.color = color; } public void Dispose() { GUI.color = _oldColor; } } } } ================================================ FILE: VirtueSky/Inspector/Editor/Utilities/TriGuiHelper.cs.meta ================================================ fileFormatVersion: 2 guid: 787c857ae9a64fdbb01e6ced9309a09e timeCreated: 1639377094 ================================================ FILE: VirtueSky/Inspector/Editor/Utilities/TriManagedReferenceGui.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using VirtueSky.InspectorUnityInternalBridge; using UnityEditor; using UnityEditor.IMGUI.Controls; using UnityEngine; using Object = UnityEngine.Object; namespace VirtueSky.Inspector.Utilities { internal static class TriManagedReferenceGui { public static void DrawTypeSelector(Rect rect, TriProperty property) { var typeName = property.ValueType != null ? TriTypeUtilities.GetTypeNiceName(property.ValueType) : "[None]"; var typeNameContent = new GUIContent(typeName); if (EditorGUI.DropdownButton(rect, typeNameContent, FocusType.Passive)) { var dropdown = new ReferenceTypeDropDown(property, new AdvancedDropdownState()); dropdown.Show(rect); if (dropdown.CanHideHeader) { AdvancedDropdownProxy.SetShowHeader(dropdown, false); } Event.current.Use(); } } private class ReferenceTypeDropDown : AdvancedDropdown { private readonly TriProperty _property; public bool CanHideHeader { get; private set; } public ReferenceTypeDropDown(TriProperty property, AdvancedDropdownState state) : base(state) { _property = property; minimumSize = new Vector2(0, 120); } protected override AdvancedDropdownItem BuildRoot() { var types = TriReflectionUtilities .AllNonAbstractTypes .Where(type => !typeof(Object).IsAssignableFrom(type)) .Where(type => _property.FieldType.IsAssignableFrom(type)) .Where(type => type.IsValueType || type.GetConstructor(Type.EmptyTypes) != null) .ToList(); var groupByNamespace = types.Count > 20; CanHideHeader = !groupByNamespace; var root = new ReferenceTypeGroupItem("Type"); root.AddChild(new ReferenceTypeItem(null)); root.AddSeparator(); foreach (var type in types) { IEnumerable namespaceEnumerator = groupByNamespace && type.Namespace != null ? type.Namespace.Split('.') : Array.Empty(); root.AddTypeChild(type, namespaceEnumerator.GetEnumerator()); } root.Build(); return root; } protected override void ItemSelected(AdvancedDropdownItem item) { if (!(item is ReferenceTypeItem referenceTypeItem)) { return; } if (referenceTypeItem.Type == null) { _property.SetValue(null); } else { var instance = Activator.CreateInstance(referenceTypeItem.Type); _property.SetValue(instance); } } private class ReferenceTypeGroupItem : AdvancedDropdownItem { private static readonly Texture2D ScriptIcon = EditorGUIUtility.FindTexture("cs Script Icon"); private readonly List _childItems = new List(); private readonly Dictionary _childGroups = new Dictionary(); public ReferenceTypeGroupItem(string name) : base(name) { } public void AddTypeChild(Type type, IEnumerator namespaceRemaining) { if (!namespaceRemaining.MoveNext()) { _childItems.Add(new ReferenceTypeItem(type, ScriptIcon)); return; } var ns = namespaceRemaining.Current ?? ""; if (!_childGroups.TryGetValue(ns, out var child)) { _childGroups[ns] = child = new ReferenceTypeGroupItem(ns); } child.AddTypeChild(type, namespaceRemaining); } public void Build() { foreach (var child in _childGroups.Values.OrderBy(it => it.name)) { AddChild(child); child.Build(); } AddSeparator(); foreach (var child in _childItems) { AddChild(child); } } } private class ReferenceTypeItem : AdvancedDropdownItem { public ReferenceTypeItem(Type type, Texture2D preview = null) : base(type != null ? TriTypeUtilities.GetTypeNiceName(type) : "[None]") { Type = type; icon = preview; } public Type Type { get; } } } } } ================================================ FILE: VirtueSky/Inspector/Editor/Utilities/TriManagedReferenceGui.cs.meta ================================================ fileFormatVersion: 2 guid: d625706e14d8480a9ab71980d1eb1e48 timeCreated: 1638804204 ================================================ FILE: VirtueSky/Inspector/Editor/Utilities/TriReflectionUtilities.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using UnityEditor; namespace VirtueSky.Inspector.Utilities { internal static class TriReflectionUtilities { private static readonly Dictionary> AttributesCache = new Dictionary>(); private static IReadOnlyList _assemblies; private static IReadOnlyList _allNonAbstractTypesBackingField; public static IReadOnlyList Assemblies { get { if (_assemblies == null) { _assemblies = AppDomain.CurrentDomain.GetAssemblies(); } return _assemblies; } } public static IReadOnlyList AllNonAbstractTypes { get { if (_allNonAbstractTypesBackingField == null) { _allNonAbstractTypesBackingField = Assemblies .SelectMany(asm => { try { return asm.GetTypes(); } catch (ReflectionTypeLoadException) { return Array.Empty(); } }) .Where(type => !type.IsAbstract) .ToList(); } return _allNonAbstractTypesBackingField; } } public static IReadOnlyList GetAttributesCached(Type type) { if (AttributesCache.TryGetValue(type, out var attributes)) { return attributes; } return AttributesCache[type] = type.GetCustomAttributes().ToList(); } public static IReadOnlyList GetCustomAttributes(this Assembly asm) { return asm.GetCustomAttributes(typeof(T)).Cast().ToList(); } public static IReadOnlyList GetAllInstanceFieldsInDeclarationOrder(Type type) { const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly; return GetAllMembersInDeclarationOrder(type, it => it.GetFields(flags)); } public static IReadOnlyList GetAllInstancePropertiesInDeclarationOrder(Type type) { const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly; return GetAllMembersInDeclarationOrder(type, it => it.GetProperties(flags)); } public static IReadOnlyList GetAllInstanceMethodsInDeclarationOrder(Type type) { const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly; return GetAllMembersInDeclarationOrder(type, it => it.GetMethods(flags)); } public static bool IsArrayOrList(Type type, out Type elementType) { if (type.IsArray) { elementType = type.GetElementType(); return true; } if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>)) { elementType = type.GetGenericArguments().Single(); return true; } elementType = null; return false; } public static Type GetUnityEditorTypeByFullName(string name) { return GetTypeByFullName(name, typeof(Editor).Assembly); } public static Type GetTypeByFullName(string name, Assembly assembly) { return assembly .GetTypes() .Single(it => it.FullName == name); } public static bool TryFindTypeByFullName(string name, out Type type) { type = Type.GetType(name); if (type != null) { return true; } foreach (var assembly in Assemblies) { type = assembly.GetType(name); if (type != null) { return true; } } return false; } private static IReadOnlyList GetAllMembersInDeclarationOrder( Type type, Func select) where T : MemberInfo { var result = new List(); var typeTree = new Stack(); while (type != null) { typeTree.Push(type); type = type.BaseType; } foreach (var t in typeTree) { var items = select(t); result.AddRange(items); } return result; } } } ================================================ FILE: VirtueSky/Inspector/Editor/Utilities/TriReflectionUtilities.cs.meta ================================================ fileFormatVersion: 2 guid: 5e3f587ee2e04832bc8cd5cfcd937f32 timeCreated: 1638857968 ================================================ FILE: VirtueSky/Inspector/Editor/Utilities/TriTypeUtilities.cs ================================================ using System; using System.Collections.Generic; namespace VirtueSky.Inspector.Utilities { public static class TriTypeUtilities { private static readonly Dictionary TypeNiceNames = new Dictionary(); public static string GetTypeNiceName(Type type) { if (TypeNiceNames.TryGetValue(type, out var niceName)) { return niceName; } niceName = type.Name; while (type.DeclaringType != null) { niceName = type.DeclaringType.Name + "." + niceName; type = type.DeclaringType; } TypeNiceNames[type] = niceName; return niceName; } } } ================================================ FILE: VirtueSky/Inspector/Editor/Utilities/TriTypeUtilities.cs.meta ================================================ fileFormatVersion: 2 guid: cd64ca1178f24265a0eea33c5dfbb3c9 timeCreated: 1690816481 ================================================ FILE: VirtueSky/Inspector/Editor/Utilities/TriUnityInspectorUtilities.cs ================================================ using System.Collections.Generic; using System.Reflection; using UnityEngine; namespace VirtueSky.Inspector.Utilities { public class TriUnityInspectorUtilities { private static readonly Dictionary StandardArrayElementNames = new Dictionary(); private static readonly FieldInfo GUIStyleNameBackingField = typeof(GUIStyle) .GetField("m_Name", BindingFlags.Instance | BindingFlags.NonPublic); public static bool MustDrawWithUnity(TriProperty property) { if (property.FieldType == typeof(GUIStyle) || property.FieldType == typeof(RectOffset)) { return true; } return !property.IsArray && property.TryGetAttribute(out DrawWithUnityAttribute _); } public static string GetStandardArrayElementName(TriProperty property) { var index = property.IndexInArray; if (!StandardArrayElementNames.TryGetValue(index, out var name)) { StandardArrayElementNames[index] = name = $"Element {index}"; } return name; } public static bool TryGetSpecialArrayElementName(TriProperty property, out string name) { if (property.FieldType == typeof(GUIStyle) && property.Value is GUIStyle guiStyle) { GUIStyleNameBackingField?.SetValue(guiStyle, null); name = guiStyle.name; return true; } if (property.PropertyType == TriPropertyType.Generic && property.ChildrenProperties.Count > 0 && property.ChildrenProperties[0] is var firstChild && firstChild.ValueType == typeof(string) && firstChild.Value is string firstChildValueStr && !string.IsNullOrEmpty(firstChildValueStr)) { name = firstChildValueStr; return true; } name = default; return false; } } } ================================================ FILE: VirtueSky/Inspector/Editor/Utilities/TriUnityInspectorUtilities.cs.meta ================================================ fileFormatVersion: 2 guid: 239f16a6fc1543b8b131493585c954b3 timeCreated: 1668183919 ================================================ FILE: VirtueSky/Inspector/Editor/Utilities/TriUnitySerializationUtilities.cs ================================================ using System; using System.Collections.Generic; using System.Reflection; using UnityEngine; using Object = UnityEngine.Object; namespace VirtueSky.Inspector.Utilities { internal static class TriUnitySerializationUtilities { private static readonly Assembly CoreLibAssembly = typeof(List<>).Assembly; private static readonly Assembly SystemCoreAssembly = typeof(HashSet<>).Assembly; private static readonly Assembly SystemAssembly = typeof(LinkedList<>).Assembly; public static bool IsSerializableByUnity(FieldInfo fieldInfo) { if (fieldInfo.IsInitOnly) { return false; } if (fieldInfo.GetCustomAttribute() != null || fieldInfo.GetCustomAttribute() != null) { return false; } if (fieldInfo.GetCustomAttribute() != null) { // if it's a list or array, the base type should be serializable if (fieldInfo.FieldType.IsArray) { var type = fieldInfo.FieldType.GetElementType(); if (type.IsSerializable || type.IsInterface) return true; else return false; } else if (fieldInfo.FieldType.IsGenericType && fieldInfo.FieldType.GetGenericTypeDefinition() == typeof(List<>)) { var type = fieldInfo.FieldType.GenericTypeArguments[0]; if (type.IsSerializable || type.IsInterface) return true; else return false; } else { return true; } } if (fieldInfo.IsPublic || fieldInfo.GetCustomAttribute() != null) { return IsTypeSerializable(fieldInfo.FieldType); } return false; } public static bool IsTypeSerializable(Type type, bool allowCollections = true) { if (type == typeof(object) || type.IsInterface) { return false; } if (type.IsEnum) { var underlyingType = Enum.GetUnderlyingType(type); return underlyingType != typeof(long) && underlyingType != typeof(ulong); } if (type.IsPrimitive || type == typeof(string) || type == typeof(Vector2) || type == typeof(Vector2Int) || type == typeof(Vector3) || type == typeof(Vector3Int) || type == typeof(Vector4) || type == typeof(Color) || type == typeof(Color32) || type == typeof(LayerMask) || type == typeof(Rect) || type == typeof(RectInt) || type == typeof(AnimationCurve) || type == typeof(Bounds) || type == typeof(BoundsInt) || type == typeof(Gradient) || type == typeof(Quaternion)) { return true; } if (typeof(Object).IsAssignableFrom(type)) { return true; } if (typeof(Delegate).IsAssignableFrom(type)) { return false; } if (type.IsArray) { var elementType = type.GetElementType(); return type.GetArrayRank() == 1 && allowCollections && IsTypeSerializable(elementType, allowCollections: false); } if (type.IsGenericType) { var genericTypeDefinition = type.GetGenericTypeDefinition(); if (genericTypeDefinition == typeof(List<>)) { var elementType = type.GetGenericArguments()[0]; return allowCollections && IsTypeSerializable(elementType, allowCollections: false); } if (genericTypeDefinition == typeof(Dictionary<,>)) { return false; } } if (type.Assembly == CoreLibAssembly || type.Assembly == SystemAssembly || type.Assembly == SystemCoreAssembly) { return false; } if (type.GetCustomAttribute() != null) { return true; } // any other cases? return false; } internal static object PopulateUnityDefaultValueForType(Type type) { if (type == typeof(string)) { return string.Empty; } if (typeof(Object).IsAssignableFrom(type)) { return null; } if (type.IsEnum) { var values = Enum.GetValues(type); return values.Length > 0 ? values.GetValue(0) : Enum.ToObject(type, 0); } if (type.IsValueType) { return Activator.CreateInstance(type); } if (type.IsArray && type.GetElementType() is var elementType && elementType != null) { return Array.CreateInstance(elementType, 0); } if (type.GetConstructor(Type.EmptyTypes) != null) { return Activator.CreateInstance(type); } return null; } } } ================================================ FILE: VirtueSky/Inspector/Editor/Utilities/TriUnitySerializationUtilities.cs.meta ================================================ fileFormatVersion: 2 guid: eadfe6520116444e8da02fcd54916d85 timeCreated: 1639381952 ================================================ FILE: VirtueSky/Inspector/Editor/Utilities.meta ================================================ fileFormatVersion: 2 guid: 52ef049660d64f2f9b2966acfb8d3447 timeCreated: 1638773133 ================================================ FILE: VirtueSky/Inspector/Editor/ValidatorsDrawer.cs ================================================ using System; using System.Collections.Generic; using VirtueSky.Inspector.Elements; using UnityEditor; namespace VirtueSky.Inspector { internal class ValidatorsDrawer : TriCustomDrawer { public override TriElement CreateElementInternal(TriProperty property, TriElement next) { if (!property.HasValidators) { return next; } var element = new TriElement(); element.AddChild(new TriPropertyValidationResultElement(property)); element.AddChild(next); return element; } public class TriPropertyValidationResultElement : TriElement { private readonly TriProperty _property; private IReadOnlyList _validationResults; public TriPropertyValidationResultElement(TriProperty property) { _property = property; } public override float GetHeight(float width) { if (ChildrenCount == 0) { return -EditorGUIUtility.standardVerticalSpacing; } return base.GetHeight(width); } public override bool Update() { var dirty = base.Update(); dirty |= GenerateValidationResults(); return dirty; } private bool GenerateValidationResults() { if (ReferenceEquals(_property.ValidationResults, _validationResults)) { return false; } _validationResults = _property.ValidationResults; RemoveAllChildren(); foreach (var result in _validationResults) { var infoBox = result.FixAction != null ? new TriInfoBoxElement(result.Message, result.MessageType, inlineAction: () => ExecuteFix(result.FixAction), inlineActionContent: result.FixActionContent) : new TriInfoBoxElement(result.Message, result.MessageType); AddChild(infoBox); } return true; } private void ExecuteFix(Action fixAction) { _property.ModifyAndRecordForUndo(targetIndex => fixAction?.Invoke()); } } } } ================================================ FILE: VirtueSky/Inspector/Editor/ValidatorsDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: 70da4f7e93ab42ffa7b39c465d2d33e1 timeCreated: 1652969657 ================================================ FILE: VirtueSky/Inspector/Editor/VirtueSky.Sunflower.Inspector.Editor.asmdef ================================================ { "name": "VirtueSky.Sunflower.Inspector.Editor", "rootNamespace": "", "references": [ "Unity.InternalAPIEditorBridge.013", "VirtueSky.Sunflower.Inspector", "Virtuesky.Sunflower.Utils" ], "includePlatforms": [ "Editor" ], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": true, "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], "versionDefines": [], "noEngineReferences": false } ================================================ FILE: VirtueSky/Inspector/Editor/VirtueSky.Sunflower.Inspector.Editor.asmdef.meta ================================================ fileFormatVersion: 2 guid: e851236b9ac2b9b4eaaa99506366edea AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Drawers/BuiltinDrawerBase.cs ================================================ using UnityEditor; using UnityEngine; namespace VirtueSky.Inspector.Drawers { public abstract class BuiltinDrawerBase : TriValueDrawer { public sealed override TriElement CreateElement(TriValue propertyValue, TriElement next) { if (propertyValue.Property.TryGetSerializedProperty(out _)) { return next; } return base.CreateElement(propertyValue, next); } public virtual int CompactModeLines => 1; public virtual int WideModeLines => 1; public sealed override float GetHeight(float width, TriValue propertyValue, TriElement next) { var lineHeight = EditorGUIUtility.singleLineHeight; var spacing = EditorGUIUtility.standardVerticalSpacing; var lines = EditorGUIUtility.wideMode ? WideModeLines : CompactModeLines; return lineHeight * lines + spacing * (lines - 1); } public sealed override void OnGUI(Rect position, TriValue propertyValue, TriElement next) { var value = propertyValue.SmartValue; EditorGUI.BeginChangeCheck(); value = OnValueGUI(position, propertyValue.Property.DisplayNameContent, value); if (EditorGUI.EndChangeCheck()) { propertyValue.SetValue(value); } } protected abstract T OnValueGUI(Rect position, GUIContent label, T value); } } ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Drawers/BuiltinDrawerBase.cs.meta ================================================ fileFormatVersion: 2 guid: 1099ac0317654a238e210dec14c7ea89 timeCreated: 1641570232 ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Drawers/BuiltinDrawers.cs ================================================ using System; using VirtueSky.Inspector; using VirtueSky.Inspector.Drawers; using UnityEditor; using UnityEditorInternal; using UnityEngine; [assembly: RegisterTriValueDrawer(typeof(IntegerDrawer), TriDrawerOrder.Fallback)] [assembly: RegisterTriValueDrawer(typeof(LongDrawer), TriDrawerOrder.Fallback)] [assembly: RegisterTriValueDrawer(typeof(BooleanDrawer), TriDrawerOrder.Fallback)] [assembly: RegisterTriValueDrawer(typeof(FloatDrawer), TriDrawerOrder.Fallback)] [assembly: RegisterTriValueDrawer(typeof(StringDrawer), TriDrawerOrder.Fallback)] [assembly: RegisterTriValueDrawer(typeof(ColorDrawer), TriDrawerOrder.Fallback)] [assembly: RegisterTriValueDrawer(typeof(Color32Drawer), TriDrawerOrder.Fallback)] [assembly: RegisterTriValueDrawer(typeof(LayerMaskDrawer), TriDrawerOrder.Fallback)] [assembly: RegisterTriValueDrawer(typeof(EnumDrawer), TriDrawerOrder.Fallback)] [assembly: RegisterTriValueDrawer(typeof(Vector2Drawer), TriDrawerOrder.Fallback)] [assembly: RegisterTriValueDrawer(typeof(Vector3Drawer), TriDrawerOrder.Fallback)] [assembly: RegisterTriValueDrawer(typeof(Vector4Drawer), TriDrawerOrder.Fallback)] [assembly: RegisterTriValueDrawer(typeof(RectDrawer), TriDrawerOrder.Fallback)] [assembly: RegisterTriValueDrawer(typeof(AnimationCurveDrawer), TriDrawerOrder.Fallback)] [assembly: RegisterTriValueDrawer(typeof(BoundsDrawer), TriDrawerOrder.Fallback)] [assembly: RegisterTriValueDrawer(typeof(GradientDrawer), TriDrawerOrder.Fallback)] [assembly: RegisterTriValueDrawer(typeof(Vector2IntDrawer), TriDrawerOrder.Fallback)] [assembly: RegisterTriValueDrawer(typeof(Vector3IntDrawer), TriDrawerOrder.Fallback)] [assembly: RegisterTriValueDrawer(typeof(RectIntDrawer), TriDrawerOrder.Fallback)] [assembly: RegisterTriValueDrawer(typeof(BoundsIntDrawer), TriDrawerOrder.Fallback)] namespace VirtueSky.Inspector.Drawers { public class StringDrawer : BuiltinDrawerBase { protected override string OnValueGUI(Rect position, GUIContent label, string value) { return EditorGUI.TextField(position, label, value); } } public class BooleanDrawer : BuiltinDrawerBase { protected override bool OnValueGUI(Rect position, GUIContent label, bool value) { return EditorGUI.Toggle(position, label, value); } } public class IntegerDrawer : BuiltinDrawerBase { protected override int OnValueGUI(Rect position, GUIContent label, int value) { return EditorGUI.IntField(position, label, value); } } public class LongDrawer : BuiltinDrawerBase { protected override long OnValueGUI(Rect position, GUIContent label, long value) { return EditorGUI.LongField(position, label, value); } } public class FloatDrawer : BuiltinDrawerBase { protected override float OnValueGUI(Rect position, GUIContent label, float value) { return EditorGUI.FloatField(position, label, value); } } public class ColorDrawer : BuiltinDrawerBase { protected override Color OnValueGUI(Rect position, GUIContent label, Color value) { return EditorGUI.ColorField(position, label, value); } } public class Color32Drawer : BuiltinDrawerBase { protected override Color32 OnValueGUI(Rect position, GUIContent label, Color32 value) { return EditorGUI.ColorField(position, label, value); } } public class LayerMaskDrawer : BuiltinDrawerBase { protected override LayerMask OnValueGUI(Rect position, GUIContent label, LayerMask value) { var mask = InternalEditorUtility.LayerMaskToConcatenatedLayersMask(value); var layers = InternalEditorUtility.layers; position = EditorGUI.PrefixLabel(position, label); return EditorGUI.MaskField(position, mask, layers); } } public class EnumDrawer : BuiltinDrawerBase { protected override Enum OnValueGUI(Rect position, GUIContent label, Enum value) { return EditorGUI.EnumPopup(position, label, value); } } public class Vector2Drawer : BuiltinDrawerBase { public override int CompactModeLines => 2; protected override Vector2 OnValueGUI(Rect position, GUIContent label, Vector2 value) { return EditorGUI.Vector2Field(position, label, value); } } public class Vector3Drawer : BuiltinDrawerBase { public override int CompactModeLines => 2; protected override Vector3 OnValueGUI(Rect position, GUIContent label, Vector3 value) { return EditorGUI.Vector3Field(position, label, value); } } public class Vector4Drawer : BuiltinDrawerBase { public override int CompactModeLines => 2; protected override Vector4 OnValueGUI(Rect position, GUIContent label, Vector4 value) { return EditorGUI.Vector4Field(position, label, value); } } public class RectDrawer : BuiltinDrawerBase { public override int CompactModeLines => 3; public override int WideModeLines => 2; protected override Rect OnValueGUI(Rect position, GUIContent label, Rect value) { return EditorGUI.RectField(position, label, value); } } public class AnimationCurveDrawer : BuiltinDrawerBase { protected override AnimationCurve OnValueGUI(Rect position, GUIContent label, AnimationCurve value) { return EditorGUI.CurveField(position, label, value); } } public class BoundsDrawer : BuiltinDrawerBase { public override int CompactModeLines => 3; public override int WideModeLines => 3; protected override Bounds OnValueGUI(Rect position, GUIContent label, Bounds value) { return EditorGUI.BoundsField(position, label, value); } } public class GradientDrawer : BuiltinDrawerBase { private static readonly GUIContent NullLabel = new GUIContent("Gradient is null"); protected override Gradient OnValueGUI(Rect position, GUIContent label, Gradient value) { if (value == null) { EditorGUI.LabelField(position, label, NullLabel); return null; } return EditorGUI.GradientField(position, label, value); } } public class Vector2IntDrawer : BuiltinDrawerBase { public override int CompactModeLines => 2; protected override Vector2Int OnValueGUI(Rect position, GUIContent label, Vector2Int value) { return EditorGUI.Vector2IntField(position, label, value); } } public class Vector3IntDrawer : BuiltinDrawerBase { public override int CompactModeLines => 2; protected override Vector3Int OnValueGUI(Rect position, GUIContent label, Vector3Int value) { return EditorGUI.Vector3IntField(position, label, value); } } public class RectIntDrawer : BuiltinDrawerBase { public override int CompactModeLines => 3; public override int WideModeLines => 2; protected override RectInt OnValueGUI(Rect position, GUIContent label, RectInt value) { return EditorGUI.RectIntField(position, label, value); } } public class BoundsIntDrawer : BuiltinDrawerBase { public override int CompactModeLines => 3; public override int WideModeLines => 3; protected override BoundsInt OnValueGUI(Rect position, GUIContent label, BoundsInt value) { return EditorGUI.BoundsIntField(position, label, value); } } } ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Drawers/BuiltinDrawers.cs.meta ================================================ fileFormatVersion: 2 guid: e7795a3fa9734e729f1567c86c4926c5 timeCreated: 1639317854 ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Drawers/ButtonDrawer.cs ================================================ using System; using System.Reflection; using VirtueSky.Inspector; using VirtueSky.Inspector.Drawers; using VirtueSky.Inspector.Elements; using VirtueSky.Inspector.Resolvers; using VirtueSky.Inspector.Utilities; using UnityEditor; using UnityEngine; [assembly: RegisterTriAttributeDrawer(typeof(ButtonDrawer), TriDrawerOrder.Drawer)] namespace VirtueSky.Inspector.Drawers { public class ButtonDrawer : TriAttributeDrawer { private ValueResolver _nameResolver; public override TriExtensionInitializationResult Initialize(TriPropertyDefinition propertyDefinition) { var isValidMethod = propertyDefinition.TryGetMemberInfo(out var memberInfo) && memberInfo is MethodInfo; if (!isValidMethod) { return "[Button] valid only on methods"; } _nameResolver = ValueResolver.ResolveString(propertyDefinition, Attribute.Name); if (_nameResolver.TryGetErrorString(out var error)) { return error; } return TriExtensionInitializationResult.Ok; } public override TriElement CreateElement(TriProperty property, TriElement next) { return new TriButtonElement(property, Attribute, _nameResolver); } private class TriButtonElement : TriHeaderGroupBaseElement { private readonly TriProperty _property; private readonly ButtonAttribute _attribute; private readonly ValueResolver _nameResolver; private readonly object[] _invocationArgs; public TriButtonElement(TriProperty property, ButtonAttribute attribute, ValueResolver nameResolver) { _property = property; _attribute = attribute; _nameResolver = nameResolver; var mi = property.TryGetMemberInfo(out var memberInfo) ? (MethodInfo) memberInfo : throw new Exception("TriButtonElement requires MethodInfo"); var parameters = mi.GetParameters(); _invocationArgs = new object[parameters.Length]; for (var i = 0; i < parameters.Length; i++) { var pIndex = i; var pInfo = parameters[pIndex]; if (pInfo.HasDefaultValue) { _invocationArgs[pIndex] = pInfo.DefaultValue; } var pTriDefinition = TriPropertyDefinition.CreateForGetterSetter( pIndex, pInfo.Name, pInfo.ParameterType, ((self, targetIndex) => _invocationArgs[pIndex]), ((self, targetIndex, value) => _invocationArgs[pIndex] = value)); var pTriProperty = new TriProperty(_property.PropertyTree, _property, pTriDefinition, null); AddChild(new TriPropertyElement(pTriProperty)); } } protected override float GetHeaderHeight(float width) { return GetButtonHeight(); } protected override void DrawHeader(Rect position) { if (_invocationArgs.Length > 0) { TriEditorGUI.DrawBox(position, TriEditorStyles.TabOnlyOne); } var name = _nameResolver.GetValue(_property); if (string.IsNullOrEmpty(name)) { name = _property.DisplayName; } if (string.IsNullOrEmpty(name)) { name = _property.RawName; } var buttonRect = new Rect(position) { height = GetButtonHeight(), }; if (GUI.Button(buttonRect, name)) { InvokeButton(_property, _invocationArgs); } } private float GetButtonHeight() { return _attribute.ButtonSize != 0 ? _attribute.ButtonSize : EditorGUIUtility.singleLineHeight; } } private static void InvokeButton(TriProperty property, object[] parameters) { if (property.TryGetMemberInfo(out var memberInfo) && memberInfo is MethodInfo methodInfo) { property.ModifyAndRecordForUndo(targetIndex => { try { var parentValue = property.Parent.GetValue(targetIndex); methodInfo.Invoke(parentValue, parameters); } catch (Exception e) { Debug.LogException(e); } }); } } } } ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Drawers/ButtonDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: 72993eec72494727a60c1ddf2f29abab timeCreated: 1642527717 ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Drawers/CustomBuiltInDrawer.cs ================================================ using VirtueSky.Inspector; using VirtueSky.Inspector.Drawers; using VirtueSky.Inspector.Editors; using VirtueSky.Inspector.Elements; using VirtueSky.Inspector.Utilities; using VirtueSky.InspectorUnityInternalBridge; [assembly: RegisterTriValueDrawer(typeof(CustomBuiltInDrawer), TriDrawerOrder.Fallback - 999)] namespace VirtueSky.Inspector.Drawers { public class CustomBuiltInDrawer : TriValueDrawer { public override TriElement CreateElement(TriValue propertyValue, TriElement next) { var property = propertyValue.Property; if (property.TryGetSerializedProperty(out var serializedProperty)) { var handler = ScriptAttributeUtilityProxy.GetHandler(serializedProperty); var drawWithHandler = handler.hasPropertyDrawer || property.PropertyType == TriPropertyType.Primitive || TriUnityInspectorUtilities.MustDrawWithUnity(property); if (drawWithHandler) { if (property.TryGetAttribute(out DrawWithUnityAttribute withUnityAttribute) && withUnityAttribute.WithUiToolkit) { handler.SetPreferredLabel(property.DisplayName); var visualElement = handler.CreatePropertyGUI(serializedProperty); if (visualElement != null && TriEditorCore.UiElementsRoots.TryGetValue(property.PropertyTree, out var rootElement)) { return new TriUiToolkitPropertyElement(property, serializedProperty, visualElement, rootElement); } } return new TriBuiltInPropertyElement(property, serializedProperty, handler); } } return base.CreateElement(propertyValue, next); } } } ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Drawers/CustomBuiltInDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: 01398997ba14482caf7fd7c566774973 timeCreated: 1670393704 ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Drawers/DisplayAsStringDrawer.cs ================================================ using VirtueSky.Inspector; using VirtueSky.Inspector.Drawers; using UnityEditor; using UnityEngine; [assembly: RegisterTriAttributeDrawer(typeof(DisplayAsStringDrawer), TriDrawerOrder.Decorator, ApplyOnArrayElement = true)] namespace VirtueSky.Inspector.Drawers { public class DisplayAsStringDrawer : TriAttributeDrawer { public override float GetHeight(float width, TriProperty property, TriElement next) { return EditorGUIUtility.singleLineHeight; } public override void OnGUI(Rect position, TriProperty property, TriElement next) { var value = property.Value; var text = value != null ? value.ToString() : "Null"; var controlId = GUIUtility.GetControlID(FocusType.Passive); position = EditorGUI.PrefixLabel(position, controlId, property.DisplayNameContent); GUI.Label(position, text); } } } ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Drawers/DisplayAsStringDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: 094b0ef0486f4f2faf35dba6da11e6b9 timeCreated: 1678604678 ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Drawers/DropdownDrawer.cs ================================================ using VirtueSky.Inspector; using VirtueSky.Inspector.Drawers; using VirtueSky.Inspector.Elements; using VirtueSky.Inspector.Resolvers; using UnityEngine; [assembly: RegisterTriAttributeDrawer(typeof(DropdownDrawer<>), TriDrawerOrder.Decorator, ApplyOnArrayElement = true)] namespace VirtueSky.Inspector.Drawers { public class DropdownDrawer : TriAttributeDrawer { private DropdownValuesResolver _valuesResolver; public override TriExtensionInitializationResult Initialize(TriPropertyDefinition propertyDefinition) { _valuesResolver = DropdownValuesResolver.Resolve(propertyDefinition, Attribute.Values); if (_valuesResolver.TryGetErrorString(out var error)) { return error; } return TriExtensionInitializationResult.Ok; } public override TriElement CreateElement(TriProperty property, TriElement next) { return new TriDropdownElement(property, _valuesResolver.GetDropdownItems); } } } ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Drawers/DropdownDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: 355fb8aedd1f4aca846a8bbf96558a5d timeCreated: 1656941791 ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Drawers/EnumToggleButtonsDrawer.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using VirtueSky.Inspector; using VirtueSky.Inspector.Drawers; using UnityEditor; using UnityEngine; [assembly: RegisterTriAttributeDrawer(typeof(EnumToggleButtonsDrawer), TriDrawerOrder.Drawer, ApplyOnArrayElement = true)] namespace VirtueSky.Inspector.Drawers { public class EnumToggleButtonsDrawer : TriAttributeDrawer { public override TriExtensionInitializationResult Initialize(TriPropertyDefinition propertyDefinition) { if (!propertyDefinition.FieldType.IsEnum) { return "EnumToggleButtons attribute can be used only on enums"; } return TriExtensionInitializationResult.Ok; } public override TriElement CreateElement(TriProperty property, TriElement next) { return new EnumToggleButtonsElement(property); } private sealed class EnumToggleButtonsElement : TriElement { private readonly TriProperty _property; private readonly List _enumValues; private readonly bool _isFlags; public EnumToggleButtonsElement(TriProperty property) { _property = property; _enumValues = Enum.GetNames(property.FieldType) .Zip(Enum.GetValues(property.FieldType).OfType(), (name, value) => new EnumEntry { name = name, value = value, displayName = ObjectNames.NicifyVariableName(name), }) .ToList(); _isFlags = property.FieldType.GetCustomAttributes(typeof(FlagsAttribute), false).Length > 0; var enumFields = property.FieldType.GetFields(BindingFlags.Static | BindingFlags.Public); foreach (var enumValue in _enumValues) { var enumField = Array.Find(enumFields, it => it.Name == enumValue.name); var inspectorNameAttr = enumField?.GetCustomAttribute(); if (inspectorNameAttr != null) { enumValue.displayName = inspectorNameAttr.displayName; } } _enumValues.Sort(new DeclarationOrderComparer(enumFields)); } public override float GetHeight(float width) { return EditorGUIUtility.singleLineHeight; } public override void OnGUI(Rect position) { var value = _property.TryGetSerializedProperty(out var serializedProperty) ? (Enum) Enum.ToObject(_property.FieldType, serializedProperty.longValue) : (Enum) _property.Value; var controlId = GUIUtility.GetControlID(FocusType.Passive); position = EditorGUI.PrefixLabel(position, controlId, _property.DisplayNameContent); for (var i = 0; i < _enumValues.Count; i++) { var itemRect = SplitRectWidth(position, _enumValues.Count, i); var itemStyle = GetButtonStyle(_enumValues.Count, i); var itemDisplayName = _enumValues[i].displayName; var itemValue = _enumValues[i].value; var oldSelected = value != null && (_isFlags ? value.HasFlag(itemValue) : value.Equals(itemValue)); var newSelected = GUI.Toggle(itemRect, oldSelected, itemDisplayName, itemStyle); if (oldSelected != newSelected) { if (_isFlags) { var newValue = newSelected ? (Convert.ToInt64(value) | Convert.ToInt64(itemValue)) : (Convert.ToInt64(value) & ~Convert.ToInt64(itemValue)); _property.SetValue((Enum) Enum.ToObject(_property.FieldType, newValue)); } else { _property.SetValue(itemValue); } } } } private static GUIStyle GetButtonStyle(int total, int current) { if (total <= 1) { return EditorStyles.miniButton; } if (current == 0) { return EditorStyles.miniButtonLeft; } if (current == total - 1) { return EditorStyles.miniButtonRight; } return EditorStyles.miniButtonMid; } private static Rect SplitRectWidth(Rect rect, int total, int current) { if (total == 0) { return rect; } rect.width /= total; rect.x += rect.width * current; return rect; } private class EnumEntry { public string name; public string displayName; public Enum value; } private class DeclarationOrderComparer : IComparer { private readonly FieldInfo[] _fields; public DeclarationOrderComparer(FieldInfo[] fields) { _fields = fields; } public int Compare(EnumEntry x, EnumEntry y) { var orderX = Array.FindIndex(_fields, it => it.Name == x.name); var orderY = Array.FindIndex(_fields, it => it.Name == y.name); return orderX.CompareTo(orderY); } } } } } ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Drawers/EnumToggleButtonsDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: 4f78353120e744dead6caed9c9891e25 timeCreated: 1653817544 ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Drawers/GUIColorDrawer.cs ================================================ using JetBrains.Annotations; using VirtueSky.Inspector; using VirtueSky.Inspector.Drawers; using VirtueSky.Inspector.Resolvers; using UnityEngine; [assembly: RegisterTriAttributeDrawer(typeof(GUIColorDrawer), TriDrawerOrder.Decorator)] namespace VirtueSky.Inspector.Drawers { public class GUIColorDrawer : TriAttributeDrawer { [CanBeNull] private ValueResolver _colorResolver; public override TriExtensionInitializationResult Initialize(TriPropertyDefinition propertyDefinition) { if (!string.IsNullOrEmpty(Attribute.GetColor)) { _colorResolver = ValueResolver.Resolve(propertyDefinition, Attribute.GetColor); } if (_colorResolver != null && _colorResolver.TryGetErrorString(out var error)) { return error; } return TriExtensionInitializationResult.Ok; } public override void OnGUI(Rect position, TriProperty property, TriElement next) { var oldColor = GUI.color; var newColor = _colorResolver?.GetValue(property, Color.white) ?? Attribute.Color; GUI.color = newColor; GUI.contentColor = newColor; next.OnGUI(position); GUI.color = oldColor; GUI.contentColor = oldColor; } } } ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Drawers/GUIColorDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: 3e34331cbcd3451cb18c9cc11c43f7b3 timeCreated: 1638943578 ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Drawers/IndentDrawer.cs ================================================ using VirtueSky.Inspector; using VirtueSky.Inspector.Drawers; using VirtueSky.Inspector.Utilities; using UnityEngine; [assembly: RegisterTriAttributeDrawer(typeof(IndentDrawer), TriDrawerOrder.Decorator)] namespace VirtueSky.Inspector.Drawers { public class IndentDrawer : TriAttributeDrawer { public override void OnGUI(Rect position, TriProperty property, TriElement next) { using (var indentedRectScope = TriGuiHelper.PushIndentedRect(position, Attribute.Indent)) { next.OnGUI(indentedRectScope.IndentedRect); } } } } ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Drawers/IndentDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: 53bdb27623d2437a9af368e1342d9176 timeCreated: 1638947263 ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Drawers/InlineEditorDrawer.cs ================================================ using VirtueSky.Inspector; using VirtueSky.Inspector.Drawers; using VirtueSky.Inspector.Elements; using VirtueSky.Inspector.Utilities; using UnityEditor; using UnityEngine; using Object = UnityEngine.Object; [assembly: RegisterTriAttributeDrawer(typeof(InlineEditorDrawer), TriDrawerOrder.Decorator, ApplyOnArrayElement = true)] namespace VirtueSky.Inspector.Drawers { public class InlineEditorDrawer : TriAttributeDrawer { public override TriExtensionInitializationResult Initialize(TriPropertyDefinition propertyDefinition) { if (!typeof(Object).IsAssignableFrom(propertyDefinition.FieldType)) { return "[InlineEditor] valid only on Object fields"; } return TriExtensionInitializationResult.Ok; } public override TriElement CreateElement(TriProperty property, TriElement next) { var element = new TriBoxGroupElement(new TriBoxGroupElement.Props { titleMode = TriBoxGroupElement.TitleMode.Hidden, }); element.AddChild(new ObjectReferenceFoldoutDrawerElement(property)); element.AddChild(new InlineEditorElement(property, new InlineEditorElement.Props { mode = Attribute.Mode, previewHeight = Attribute.PreviewHeight, })); return element; } private class ObjectReferenceFoldoutDrawerElement : TriElement { private readonly TriProperty _property; public ObjectReferenceFoldoutDrawerElement(TriProperty property) { _property = property; } public override float GetHeight(float width) { return EditorGUIUtility.singleLineHeight; } public override void OnGUI(Rect position) { var prefixRect = new Rect(position) { height = EditorGUIUtility.singleLineHeight, xMax = position.xMin + EditorGUIUtility.labelWidth, }; var pickerRect = new Rect(position) { height = EditorGUIUtility.singleLineHeight, xMin = prefixRect.xMax, }; TriEditorGUI.Foldout(prefixRect, _property); EditorGUI.BeginChangeCheck(); var allowSceneObjects = _property.PropertyTree.TargetIsPersistent == false; var value = (Object) _property.Value; value = EditorGUI.ObjectField(pickerRect, GUIContent.none, value, _property.FieldType, allowSceneObjects); if (EditorGUI.EndChangeCheck()) { _property.SetValue(value); } } } } } ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Drawers/InlineEditorDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: 088c34bc4fc448b4aac18ed9bf4f9bc6 timeCreated: 1641657562 ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Drawers/LabelWidthDrawer.cs ================================================ using VirtueSky.Inspector; using VirtueSky.Inspector.Drawers; using UnityEditor; using UnityEngine; [assembly: RegisterTriAttributeDrawer(typeof(LabelWidthDrawer), TriDrawerOrder.Decorator)] namespace VirtueSky.Inspector.Drawers { public class LabelWidthDrawer : TriAttributeDrawer { public override void OnGUI(Rect position, TriProperty property, TriElement next) { var oldLabelWidth = EditorGUIUtility.labelWidth; EditorGUIUtility.labelWidth = Attribute.Width; next.OnGUI(position); EditorGUIUtility.labelWidth = oldLabelWidth; } } } ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Drawers/LabelWidthDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: d7bb028f84224ec5817b1c807ca5db86 timeCreated: 1638948103 ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Drawers/ObjectReferenceDrawer.cs ================================================ using VirtueSky.Inspector; using VirtueSky.Inspector.Drawers; using UnityEditor; using UnityEngine; [assembly: RegisterTriValueDrawer(typeof(ObjectReferenceDrawer), TriDrawerOrder.Fallback)] namespace VirtueSky.Inspector.Drawers { public class ObjectReferenceDrawer : TriValueDrawer { public override TriElement CreateElement(TriValue value, TriElement next) { if (value.Property.IsRootProperty || value.Property.TryGetSerializedProperty(out _)) { return next; } return new ObjectReferenceDrawerElement(value); } private class ObjectReferenceDrawerElement : TriElement { private TriValue _propertyValue; private readonly bool _allowSceneObjects; public ObjectReferenceDrawerElement(TriValue propertyValue) { _propertyValue = propertyValue; _allowSceneObjects = propertyValue.Property.PropertyTree.TargetIsPersistent == false; } public override float GetHeight(float width) { return EditorGUIUtility.singleLineHeight; } public override void OnGUI(Rect position) { var value = _propertyValue.SmartValue; EditorGUI.BeginChangeCheck(); value = EditorGUI.ObjectField(position, _propertyValue.Property.DisplayNameContent, value, _propertyValue.Property.FieldType, _allowSceneObjects); if (EditorGUI.EndChangeCheck()) { _propertyValue.SetValue(value); } } } } } ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Drawers/ObjectReferenceDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: 95268b41deb942b8882969bf23911eaf timeCreated: 1641571162 ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Drawers/OnValueChangedDrawer.cs ================================================ using VirtueSky.Inspector; using VirtueSky.Inspector.Drawers; using VirtueSky.Inspector.Resolvers; [assembly: RegisterTriAttributeDrawer(typeof(OnValueChangedDrawer), TriDrawerOrder.System)] namespace VirtueSky.Inspector.Drawers { public class OnValueChangedDrawer : TriAttributeDrawer { private ActionResolver _actionResolver; public override TriExtensionInitializationResult Initialize(TriPropertyDefinition propertyDefinition) { base.Initialize(propertyDefinition); _actionResolver = ActionResolver.Resolve(propertyDefinition, Attribute.Method); if (_actionResolver.TryGetErrorString(out var error)) { return error; } return TriExtensionInitializationResult.Ok; } public override TriElement CreateElement(TriProperty property, TriElement next) { return new OnValueChangedListenerElement(property, next, _actionResolver); } private class OnValueChangedListenerElement : TriElement { private readonly TriProperty _property; private readonly ActionResolver _actionResolver; public OnValueChangedListenerElement(TriProperty property, TriElement next, ActionResolver actionResolver) { _property = property; _actionResolver = actionResolver; AddChild(next); } protected override void OnAttachToPanel() { base.OnAttachToPanel(); _property.ValueChanged += OnValueChanged; _property.ChildValueChanged += OnValueChanged; } protected override void OnDetachFromPanel() { _property.ChildValueChanged -= OnValueChanged; _property.ValueChanged -= OnValueChanged; base.OnDetachFromPanel(); } private void OnValueChanged(TriProperty obj) { _property.PropertyTree.ApplyChanges(); _actionResolver.InvokeForAllTargets(_property); _property.PropertyTree.Update(); } } } } ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Drawers/OnValueChangedDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: 16bb69c0bfa84c69b1cd04863fdd1570 timeCreated: 1654159943 ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Drawers/PreviewMeshDrawer.cs ================================================ using System; using System.Linq; using VirtueSky.Inspector; using VirtueSky.Inspector.Drawers; using VirtueSky.Inspector.Elements; using VirtueSky.Inspector.Utilities; using UnityEditor; using UnityEngine; using Object = UnityEngine.Object; [assembly: RegisterTriAttributeDrawer(typeof(PreviewMeshDrawer), TriDrawerOrder.Decorator, ApplyOnArrayElement = true)] namespace VirtueSky.Inspector.Drawers { public class PreviewMeshDrawer : TriAttributeDrawer { private class PreviewMeshPicker : TriElement { private readonly TriProperty _property; private readonly bool _useFoldout; public PreviewMeshPicker(TriProperty property, bool useFoldout) { _property = property; _useFoldout = useFoldout; } public override float GetHeight(float width) { return EditorGUIUtility.singleLineHeight; } public override void OnGUI(Rect position) { var pickerRect = position; GUIContent label = new(_property.DisplayName); if (_useFoldout) { var prefixRect = new Rect(position) { height = EditorGUIUtility.singleLineHeight, xMax = position.xMin + EditorGUIUtility.labelWidth, }; pickerRect = new Rect(position) { height = EditorGUIUtility.singleLineHeight, xMin = prefixRect.xMax, }; TriEditorGUI.Foldout(prefixRect, _property); label = GUIContent.none; } EditorGUI.BeginChangeCheck(); Object obj = _property.Value as Object; var asset = EditorGUI.ObjectField(pickerRect, label, obj, typeof(GameObject), true); if (EditorGUI.EndChangeCheck()) { _property.SetValue(asset); } } } private class PreviewMesh : TriElement { private readonly int _height; private readonly int _width; private readonly TriProperty _property; private readonly bool _useFoldout; private readonly PreviewMeshRotationMethod _rotationMethod; private PreviewRenderUtility _previewUtility; private static Material _mat; private Material GetMat { get { if (_mat == null) { var shaderNames = new[] { "Universal Render Pipeline/Lit", "Standard", "Legacy Shaders/Diffuse", }; var shader = shaderNames.Select(name => Shader.Find(name)).First(shader => shader != null); _mat = new Material(shader) { hideFlags = HideFlags.HideAndDontSave, color = new Color(0.4f, 0.7f, 0.4f), }; } return _mat; } } private readonly float _c_ROTATION_SENSITIVITY = -0.5f; private readonly float _c_ZOOM_SENSITIVITY = 0.1f; private readonly float _c_ZOOM_SENSITIVITY_MIN = 2f; private readonly float _c_ZOOM_SENSITIVITY_MAX = 10f; private readonly float _c_MIN_WIDTH = 50f; private readonly float _c_DEFAULT_CAMERA_DISTANCE = 4f; private Quaternion _previewQuaternion; private Mesh _sharedMesh; private float _distance; private Vector2 _previewDir = new(-20f, 0f); #region Initialization public PreviewMesh(TriProperty property, int size, int width, bool useFoldout, PreviewMeshRotationMethod rotationMethod) { _property = property; _height = size; _width = width; _useFoldout = useFoldout; _rotationMethod = rotationMethod; } protected override void OnAttachToPanel() { _previewUtility = new(); _property.ValueChanged += OnValueChanged; // Setup lights _previewUtility.lights[0].intensity = 1.3f; _previewUtility.lights[0].transform.rotation = Quaternion.Euler(40f, 40f, 0); _previewUtility.lights[1].intensity = 1.3f; // Setup camera _previewUtility.cameraFieldOfView = 30f; _previewUtility.camera.nearClipPlane = 0.1f; _previewUtility.camera.farClipPlane = 100f; _previewUtility.camera.backgroundColor = Color.black; _previewUtility.camera.clearFlags = CameraClearFlags.Color; base.OnAttachToPanel(); GetMeshObject(); } protected override void OnDetachFromPanel() { _previewUtility.Cleanup(); _previewUtility = null; _property.ValueChanged -= OnValueChanged; base.OnDetachFromPanel(); } private void OnValueChanged(TriProperty property) { GetMeshObject(); } public override float GetHeight(float width) { if (_sharedMesh == null) { return 0f; } if (!_useFoldout || _property.IsExpanded) { return _height; } return 0f; } public override void OnGUI(Rect position) { if (_sharedMesh == null) { return; } float currentWidth = _width == -1 ? (int)position.width : _width; currentWidth = Math.Max(currentWidth, _c_MIN_WIDTH); if (position.height == 0f) { return; } position = new Rect(position.x, position.y, currentWidth, _height); _previewUtility.BeginPreview(position, GUIStyle.none); _previewUtility.DrawMesh(_sharedMesh, Matrix4x4.TRS(Vector3.zero, _previewQuaternion, Vector3.one), GetMat, 0); _previewUtility.camera.Render(); Texture result = _previewUtility.EndPreview(); if (result) { GUI.DrawTexture(position, result, ScaleMode.ScaleToFit, false); } if (position.Contains(Event.current.mousePosition)) { HandleMouseEvent(Event.current); } } #endregion #region Helper Function private void GetMeshObject() { var obj = _property.Value as Object; if (obj == null) { _sharedMesh = null; return; } _previewQuaternion = Quaternion.Euler(_previewDir); _distance = _c_DEFAULT_CAMERA_DISTANCE; // Draw supported types if (obj is Mesh mesh) { _sharedMesh = mesh; } else if (obj is GameObject go) { var mf = go.GetComponentInChildren(); if (mf != null) { _sharedMesh = mf.sharedMesh; } else { Debug.Log("No MeshFilter found on GameObject."); } } if (_sharedMesh != null) { UpdatePreviewCamera(); } } private void UpdatePreviewCamera() { var bounds = _sharedMesh.bounds; // fallback bounds if (bounds.size == Vector3.zero) { bounds = new Bounds(Vector3.zero, Vector3.one); } var magnitude = bounds.extents.magnitude; _previewUtility.camera.transform.position = bounds.center + Vector3.back * (magnitude * _distance); _previewUtility.camera.transform.LookAt(bounds.center); } private void HandleMouseEvent(Event mouseEvent) { var shift = mouseEvent.shift; switch (mouseEvent.type) { case EventType.MouseDrag: var cameraMovement = mouseEvent.delta * _c_ROTATION_SENSITIVITY; HandlePreviewCameraRotation(cameraMovement); mouseEvent.Use(); break; case EventType.ScrollWheel: _distance = Mathf.Clamp(_distance + mouseEvent.delta.x * _c_ZOOM_SENSITIVITY, _c_ZOOM_SENSITIVITY_MIN, _c_ZOOM_SENSITIVITY_MAX); if (shift) { UpdatePreviewCamera(); mouseEvent.Use(); } break; default: return; } } private void HandlePreviewCameraRotation(Vector2 movement) { float pitch = movement.y; float yaw = movement.x; switch (_rotationMethod) { case PreviewMeshRotationMethod.Clamped: _previewDir.x = Mathf.Clamp(pitch + _previewDir.x, -90f, 90); _previewDir.y += yaw; _previewQuaternion = Quaternion.Euler(_previewDir.x, 0, 0) * Quaternion.Euler(0, _previewDir.y, 0); break; case PreviewMeshRotationMethod.Freeform: _previewQuaternion = Quaternion.Euler(pitch, yaw, 0) * _previewQuaternion; break; } _previewQuaternion = Quaternion.Normalize(_previewQuaternion); } #endregion } public override TriElement CreateElement(TriProperty property, TriElement next) { var root = new TriBoxGroupElement(new TriBoxGroupElement.Props { titleMode = TriBoxGroupElement.TitleMode.Hidden, }); root.AddChild(new PreviewMeshPicker(property, Attribute.UseFoldout)); root.AddChild(new PreviewMesh(property, Attribute.Height, Attribute.Width, Attribute.UseFoldout, Attribute.RotationMethod)); return root; } } } ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Drawers/PreviewMeshDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: 2f834cedcca8433e99c9f51aca35c8ea timeCreated: 1758476267 ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Drawers/PropertySpaceDrawer.cs ================================================ using VirtueSky.Inspector; using VirtueSky.Inspector.Drawers; using UnityEngine; [assembly: RegisterTriAttributeDrawer(typeof(PropertySpaceDrawer), TriDrawerOrder.Inspector)] namespace VirtueSky.Inspector.Drawers { public class PropertySpaceDrawer : TriAttributeDrawer { public override float GetHeight(float width, TriProperty property, TriElement next) { var totalSpace = Attribute.SpaceBefore + Attribute.SpaceAfter; return next.GetHeight(width) + totalSpace; } public override void OnGUI(Rect position, TriProperty property, TriElement next) { var contentPosition = new Rect(position) { yMin = position.yMin + Attribute.SpaceBefore, yMax = position.yMax - Attribute.SpaceAfter, }; next.OnGUI(contentPosition); } } } ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Drawers/PropertySpaceDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: d703a4146e75487aa57e22f375b04c32 timeCreated: 1638942558 ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Drawers/SceneDrawer.cs ================================================ using VirtueSky.Inspector; using VirtueSky.Inspector.Drawers; using UnityEditor; using UnityEngine; [assembly: RegisterTriAttributeDrawer(typeof(SceneDrawer), TriDrawerOrder.Decorator, ApplyOnArrayElement = true)] namespace VirtueSky.Inspector.Drawers { public class SceneDrawer : TriAttributeDrawer { public override TriExtensionInitializationResult Initialize(TriPropertyDefinition propertyDefinition) { var type = propertyDefinition.FieldType; if (type != typeof(string)) { return "Scene attribute can only be used on field with string type"; } return base.Initialize(propertyDefinition); } public override TriElement CreateElement(TriProperty property, TriElement next) { return new SceneElement(property); } private class SceneElement : TriElement { private readonly TriProperty _property; private SceneAsset _sceneAsset; public SceneElement(TriProperty property) { _property = property; } protected override void OnAttachToPanel() { base.OnAttachToPanel(); _property.ValueChanged += OnValueChanged; RefreshSceneAsset(); } protected override void OnDetachFromPanel() { _property.ValueChanged -= OnValueChanged; base.OnDetachFromPanel(); } public override float GetHeight(float width) { return EditorGUIUtility.singleLineHeight; } public override void OnGUI(Rect position) { EditorGUI.BeginChangeCheck(); var asset = EditorGUI.ObjectField(position, _property.DisplayName, _sceneAsset, typeof(SceneAsset), false); if (EditorGUI.EndChangeCheck()) { var path = AssetDatabase.GetAssetPath(asset); _property.SetValue(path); } } private void OnValueChanged(TriProperty property) { RefreshSceneAsset(); } private void RefreshSceneAsset() { _sceneAsset = AssetDatabase.LoadAssetAtPath(_property.Value as string); } } } } ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Drawers/SceneDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: 47b6083a040749429c1f3371f0413847 timeCreated: 1657956568 ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Drawers/ShowDrawerChainDrawer.cs ================================================ using System.Collections.Generic; using System.Text; using VirtueSky.Inspector; using VirtueSky.Inspector.Drawers; using VirtueSky.Inspector.Elements; [assembly: RegisterTriAttributeDrawer(typeof(ShowDrawerChainDrawer), TriDrawerOrder.System)] namespace VirtueSky.Inspector.Drawers { public class ShowDrawerChainDrawer : TriAttributeDrawer { public override TriElement CreateElement(TriProperty property, TriElement next) { return new TriDrawerChainInfoElement(property.AllDrawers, next); } } public class TriDrawerChainInfoElement : TriElement { public TriDrawerChainInfoElement(IReadOnlyList drawers, TriElement next) { var info = new StringBuilder(); info.Append("Drawer Chain:"); for (var i = 0; i < drawers.Count; i++) { var drawer = drawers[i]; info.AppendLine(); info.Append(i).Append(": ").Append(drawer.GetType().Name); } AddChild(new TriInfoBoxElement(info.ToString())); AddChild(next); } } } ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Drawers/ShowDrawerChainDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: d473213c669247e48e0059471d0b6d2c timeCreated: 1639215046 ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Drawers/TableListDrawer.cs ================================================ using System; using System.Collections.Generic; using VirtueSky.Inspector; using VirtueSky.Inspector.Drawers; using VirtueSky.Inspector.Elements; using VirtueSky.Inspector.Utilities; using VirtueSky.InspectorUnityInternalBridge; using UnityEditor; using UnityEditor.IMGUI.Controls; using UnityEditorInternal; using UnityEngine; #if UNITY_6000_2_OR_NEWER using TreeView = UnityEditor.IMGUI.Controls.TreeView; using TreeViewState = UnityEditor.IMGUI.Controls.TreeViewState; using TreeViewItem = UnityEditor.IMGUI.Controls.TreeViewItem; #endif [assembly: RegisterTriAttributeDrawer(typeof(TableListDrawer), TriDrawerOrder.Drawer)] namespace VirtueSky.Inspector.Drawers { public class TableListDrawer : TriAttributeDrawer { public override TriExtensionInitializationResult Initialize(TriPropertyDefinition propertyDefinition) { if (!propertyDefinition.IsArray) { return "[TableList] valid only on lists"; } return TriExtensionInitializationResult.Ok; } public override TriElement CreateElement(TriProperty property, TriElement next) { return new TableElement(property); } private class TableElement : TriListElement { private const float FooterExtraSpace = 4; private readonly TriProperty _property; private readonly TableMultiColumnTreeView _treeView; private readonly bool _alwaysExpanded; private bool _reloadRequired; private bool _heightDirty; private bool _isExpanded; private int _arraySize; public TableElement(TriProperty property) : base(property) { _property = property; _treeView = new TableMultiColumnTreeView(property, this, ListGui) { SelectionChangedCallback = SelectionChangedCallback, }; _reloadRequired = true; } public override bool Update() { var dirty = base.Update(); dirty |= ReloadIfRequired(); if (dirty) { _heightDirty = true; _treeView.multiColumnHeader.ResizeToFit(); } return dirty; } public override float GetHeight(float width) { _treeView.Width = width; if (_heightDirty) { _heightDirty = false; _treeView.RefreshHeight(); } var height = 0f; height += ListGui.headerHeight; if (_property.IsExpanded) { height += _treeView.totalHeight; height += ListGui.footerHeight; height += FooterExtraSpace; } return height; } public override void OnGUI(Rect position) { var headerRect = new Rect(position) { height = ListGui.headerHeight, }; var elementsRect = new Rect(position) { yMin = headerRect.yMax, height = _treeView.totalHeight + FooterExtraSpace, }; var elementsContentRect = new Rect(elementsRect) { xMin = elementsRect.xMin + 1, xMax = elementsRect.xMax - 1, yMax = elementsRect.yMax - FooterExtraSpace, }; var footerRect = new Rect(position) { yMin = elementsRect.yMax, }; if (!_property.IsExpanded) { ReorderableListProxy.DoListHeader(ListGui, headerRect); return; } if (Event.current.isMouse && Event.current.type == EventType.MouseDrag) { _heightDirty = true; _treeView.multiColumnHeader.ResizeToFit(); } if (Event.current.type == EventType.Repaint) { ReorderableListProxy.defaultBehaviours.boxBackground.Draw(elementsRect, false, false, false, false); } ReorderableListProxy.DoListHeader(ListGui, headerRect); EditorGUI.BeginChangeCheck(); _treeView.OnGUI(elementsContentRect); if (EditorGUI.EndChangeCheck()) { _heightDirty = true; _property.PropertyTree.RequestRepaint(); } ReorderableListProxy.defaultBehaviours.DrawFooter(footerRect, ListGui); } private bool ReloadIfRequired() { if (!_reloadRequired && _property.IsExpanded == _isExpanded && _property.ArrayElementProperties.Count == _arraySize) { return false; } _reloadRequired = false; _isExpanded = _property.IsExpanded; _arraySize = _property.ArrayElementProperties.Count; _treeView.Reload(); return true; } protected override TriElement CreateItemElement(TriProperty property) { return new TableRowElement(property); } private void SelectionChangedCallback(int index) { ListGui.index = index; } } [Serializable] private class TableMultiColumnTreeView : TreeView { private readonly TriProperty _property; private readonly TriElement _cellElementContainer; private readonly ReorderableList _listGui; private readonly TableListPropertyOverrideContext _propertyOverrideContext; private readonly bool _showAlternatingBackground; private bool _wasRendered; public Action SelectionChangedCallback; public TableMultiColumnTreeView(TriProperty property, TriElement container, ReorderableList listGui) : base(new TreeViewState(), new TableColumnHeader()) { property.TryGetAttribute(out ListDrawerSettingsAttribute listSettings); _property = property; _cellElementContainer = container; _listGui = listGui; _showAlternatingBackground = listSettings?.ShowAlternatingBackground ?? true; _propertyOverrideContext = new TableListPropertyOverrideContext(property); showAlternatingRowBackgrounds = true; showBorder = false; useScrollView = false; multiColumnHeader.ResizeToFit(); multiColumnHeader.visibleColumnsChanged += header => header.ResizeToFit(); } public float Width { get; set; } public void RefreshHeight() { RefreshCustomRowHeights(); } protected override void SelectionChanged(IList selectedIds) { base.SelectionChanged(selectedIds); if (SelectionChangedCallback != null && selectedIds.Count == 1) { SelectionChangedCallback.Invoke(selectedIds[0]); } } protected override TreeViewItem BuildRoot() { var root = new TreeViewItem(0, -1, string.Empty); var columns = new List { new MultiColumnHeaderState.Column { width = 16, autoResize = false, canSort = false, allowToggleVisibility = false, }, }; if (_property.IsExpanded) { for (var index = 0; index < _property.ArrayElementProperties.Count; index++) { var rowChildProperty = _property.ArrayElementProperties[index]; root.AddChild(new TableTreeItem(index, rowChildProperty)); if (index == 0) { foreach (var kvp in ((TableRowElement) (_cellElementContainer.GetChild(0))).Elements) { columns.Add(new MultiColumnHeaderState.Column { headerContent = kvp.Value, headerTextAlignment = TextAlignment.Center, autoResize = true, canSort = false, }); } } } } if (root.children == null) { root.AddChild(new TableTreeEmptyItem()); } if (multiColumnHeader.state == null || multiColumnHeader.state.columns.Length == 1) { multiColumnHeader.state = new MultiColumnHeaderState(columns.ToArray()); } return root; } protected override float GetCustomRowHeight(int row, TreeViewItem item) { if (item is TableTreeEmptyItem) { return EditorGUIUtility.singleLineHeight; } var height = 0f; var rowElement = (TableRowElement) _cellElementContainer.GetChild(row); foreach (var visibleColumnIndex in multiColumnHeader.state.visibleColumns) { var cellWidth = _wasRendered ? multiColumnHeader.GetColumnRect(visibleColumnIndex).width : Width / Mathf.Max(1, multiColumnHeader.state.visibleColumns.Length); var cellHeight = visibleColumnIndex == 0 ? EditorGUIUtility.singleLineHeight : rowElement.Elements[visibleColumnIndex - 1].Key.GetHeight(cellWidth); height = Math.Max(height, cellHeight); } return height + EditorGUIUtility.standardVerticalSpacing * 2; } protected override void RowGUI(RowGUIArgs args) { if (args.item is TableTreeEmptyItem) { base.RowGUI(args); return; } if (_showAlternatingBackground && args.row % 2 != 0) { EditorGUI.DrawRect(args.rowRect, new Color(0.1f, 0.1f, 0.1f, 0.15f)); } var rowElement = (TableRowElement) _cellElementContainer.GetChild(args.row); for (var i = 0; i < multiColumnHeader.state.visibleColumns.Length; i++) { var visibleColumnIndex = multiColumnHeader.state.visibleColumns[i]; var rowIndex = args.row; var cellRect = args.GetCellRect(i); cellRect.yMin += EditorGUIUtility.standardVerticalSpacing; if (visibleColumnIndex == 0) { ReorderableListProxy.defaultBehaviours.DrawElementDraggingHandle(cellRect, rowIndex, _listGui.index == rowIndex, _listGui.index == rowIndex, _listGui.draggable); continue; } var cellElement = rowElement.Elements[visibleColumnIndex - 1].Key; cellRect.height = cellElement.GetHeight(cellRect.width); using (TriGuiHelper.PushLabelWidth(EditorGUIUtility.labelWidth / rowElement.ChildrenCount)) using (TriPropertyOverrideContext.BeginOverride(_propertyOverrideContext)) { cellElement.OnGUI(cellRect); } } _wasRendered = true; } } public class TableRowElement : TriPropertyCollectionBaseElement { public TableRowElement(TriProperty property) { DeclareGroups(property.ValueType); Elements = new List>(); if (property.PropertyType == TriPropertyType.Generic) { foreach (var childProperty in property.ChildrenProperties) { var oldChildrenCount = ChildrenCount; var props = new TriPropertyElement.Props { forceInline = true, }; AddProperty(childProperty, props, out var group); if (oldChildrenCount != ChildrenCount) { var element = GetChild(ChildrenCount - 1); var headerContent = new GUIContent(group ?? childProperty.DisplayName); Elements.Add(new KeyValuePair(element, headerContent)); } } } else { var element = new TriPropertyElement(property, new TriPropertyElement.Props { forceInline = true, }); var headerContent = new GUIContent("Element"); AddChild(element); Elements.Add(new KeyValuePair(element, headerContent)); } } public List> Elements { get; } } [Serializable] private class TableColumnHeader : MultiColumnHeader { public TableColumnHeader() : base(null) { canSort = false; height = DefaultGUI.minimumHeight; } } [Serializable] private class TableTreeEmptyItem : TreeViewItem { public TableTreeEmptyItem() : base(0, 0, "Table is Empty") { } } [Serializable] private class TableTreeItem : TreeViewItem { public TableTreeItem(int id, TriProperty property) : base(id, 0) { Property = property; } public TriProperty Property { get; } } private class TableListPropertyOverrideContext : TriPropertyOverrideContext { private readonly TriProperty _grandParentProperty; private readonly GUIContent _noneLabel = GUIContent.none; public TableListPropertyOverrideContext(TriProperty grandParentProperty) { _grandParentProperty = grandParentProperty; } public override bool TryGetDisplayName(TriProperty property, out GUIContent displayName) { if (property.PropertyType == TriPropertyType.Primitive && property.Parent?.Parent == _grandParentProperty && !property.TryGetAttribute(out GroupAttribute _)) { displayName = _noneLabel; return true; } displayName = default; return false; } } } } ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Drawers/TableListDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: 08ffdef4b26f43f5bb964ff72b883cdd timeCreated: 1642780682 ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Drawers/TitleDrawer.cs ================================================ using VirtueSky.Inspector; using VirtueSky.Inspector.Drawers; using VirtueSky.Inspector.Resolvers; using UnityEditor; using UnityEngine; [assembly: RegisterTriAttributeDrawer(typeof(TitleDrawer), TriDrawerOrder.Inspector)] namespace VirtueSky.Inspector.Drawers { public class TitleDrawer : TriAttributeDrawer { private const int SpaceBeforeTitle = 9; private const int SpaceBeforeLine = 2; private const int LineHeight = 2; private const int SpaceBeforeContent = 3; private ValueResolver _titleResolver; public override TriExtensionInitializationResult Initialize(TriPropertyDefinition propertyDefinition) { base.Initialize(propertyDefinition); _titleResolver = ValueResolver.ResolveString(propertyDefinition, Attribute.Title); if (_titleResolver.TryGetErrorString(out var error)) { return error; } return TriExtensionInitializationResult.Ok; } public override float GetHeight(float width, TriProperty property, TriElement next) { var extraHeight = SpaceBeforeTitle + EditorGUIUtility.singleLineHeight + SpaceBeforeLine + LineHeight + SpaceBeforeContent; return next.GetHeight(width) + extraHeight; } public override void OnGUI(Rect position, TriProperty property, TriElement next) { var titleRect = new Rect(position) { y = position.y + SpaceBeforeTitle, height = EditorGUIUtility.singleLineHeight, }; var lineRect = new Rect(position) { y = titleRect.yMax + SpaceBeforeLine, height = LineHeight, }; var contentRect = new Rect(position) { yMin = lineRect.yMax + SpaceBeforeContent, }; var title = _titleResolver.GetValue(property, "Error"); GUI.Label(titleRect, title, EditorStyles.boldLabel); if (Attribute.HorizontalLine) { EditorGUI.DrawRect(lineRect, Color.gray); } next.OnGUI(contentRect); } } } ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Drawers/TitleDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: 2ad25a9f98e94ba1aafe184b7fed387d timeCreated: 1638944499 ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Drawers/UnitDrawer.cs ================================================ using VirtueSky.Inspector; using VirtueSky.Inspector.Drawers; using VirtueSky.Inspector.Resolvers; using VirtueSky.Inspector.Utilities; using UnityEditor; using UnityEngine; [assembly: RegisterTriAttributeDrawer(typeof(UnitDrawer), TriDrawerOrder.Decorator)] namespace VirtueSky.Inspector.Drawers { public class UnitDrawer : TriAttributeDrawer { /// /// Defines the padding to the right of the unit label towards the editable input field /// private const int PaddingRight = 5; private ValueResolver _unitResolver; public override TriExtensionInitializationResult Initialize(TriPropertyDefinition propertyDefinition) { base.Initialize(propertyDefinition); _unitResolver = ValueResolver.ResolveString(propertyDefinition, Attribute.unitToDisplay); if (_unitResolver.TryGetErrorString(out var error)) { return error; } return TriExtensionInitializationResult.Ok; } public override void OnGUI(Rect position, TriProperty property, TriElement next) { var unit = _unitResolver.GetValue(property, ""); var size = Styles.UnitStyle.CalcSize(TriGuiHelper.TempContent(unit)); var unitRect = new Rect(position.xMax - size.x - PaddingRight, position.y, size.x, position.height); // Render the editable input field next.OnGUI(position); //Change color to grey using (TriGuiHelper.PushColor(Color.grey)) { // Render the unit as a suffix in the unitRect EditorGUI.LabelField(unitRect, unit); } } private static class Styles { public static readonly GUIStyle UnitStyle; static Styles() { UnitStyle = new GUIStyle(EditorStyles.label); } } } } ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Drawers/UnitDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: 409a22ba704c4806a28447600abae6d1 timeCreated: 1758476787 ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Drawers.meta ================================================ fileFormatVersion: 2 guid: 62b6b24478bb48c4acc0f072f2687607 timeCreated: 1639376870 ================================================ FILE: VirtueSky/Inspector/Editor.Extras/GroupDrawers/TriBoxGroupDrawer.cs ================================================ using VirtueSky.Inspector; using VirtueSky.Inspector.Elements; using VirtueSky.Inspector.GroupDrawers; [assembly: RegisterTriGroupDrawer(typeof(TriBoxGroupDrawer))] namespace VirtueSky.Inspector.GroupDrawers { public class TriBoxGroupDrawer : TriGroupDrawer { public override TriPropertyCollectionBaseElement CreateElement(DeclareBoxGroupAttribute attribute) { return new TriBoxGroupElement(new TriBoxGroupElement.Props { title = attribute.Title, titleMode = attribute.HideTitle ? TriBoxGroupElement.TitleMode.Hidden : TriBoxGroupElement.TitleMode.Normal, hideIfChildrenInvisible = true, }); } } } ================================================ FILE: VirtueSky/Inspector/Editor.Extras/GroupDrawers/TriBoxGroupDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: 735d0d9ee1cc4692ac11013b95983551 timeCreated: 1639417619 ================================================ FILE: VirtueSky/Inspector/Editor.Extras/GroupDrawers/TriFoldoutGroupDrawer.cs ================================================ using VirtueSky.Inspector; using VirtueSky.Inspector.Elements; using VirtueSky.Inspector.GroupDrawers; [assembly: RegisterTriGroupDrawer(typeof(TriFoldoutGroupDrawer))] namespace VirtueSky.Inspector.GroupDrawers { public class TriFoldoutGroupDrawer : TriGroupDrawer { public override TriPropertyCollectionBaseElement CreateElement(DeclareFoldoutGroupAttribute attribute) { return new TriBoxGroupElement(new TriBoxGroupElement.Props { title = attribute.Title, titleMode = TriBoxGroupElement.TitleMode.Foldout, expandedByDefault = attribute.Expanded, hideIfChildrenInvisible = true, }); } } } ================================================ FILE: VirtueSky/Inspector/Editor.Extras/GroupDrawers/TriFoldoutGroupDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: ebf8a67d451c4932a7502f7f220cc938 timeCreated: 1668331607 ================================================ FILE: VirtueSky/Inspector/Editor.Extras/GroupDrawers/TriHorizontalGroupDrawer.cs ================================================ using VirtueSky.Inspector; using VirtueSky.Inspector.Elements; using VirtueSky.Inspector.GroupDrawers; using UnityEngine; [assembly: RegisterTriGroupDrawer(typeof(TriHorizontalGroupDrawer))] namespace VirtueSky.Inspector.GroupDrawers { public class TriHorizontalGroupDrawer : TriGroupDrawer { public override TriPropertyCollectionBaseElement CreateElement(DeclareHorizontalGroupAttribute attribute) { return new TriHorizontalGroupElement(attribute.Sizes); } } } ================================================ FILE: VirtueSky/Inspector/Editor.Extras/GroupDrawers/TriHorizontalGroupDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: 866eb8cc0f46446b8ceb1b2cb78b344c timeCreated: 1640871674 ================================================ FILE: VirtueSky/Inspector/Editor.Extras/GroupDrawers/TriTabGroupDrawer.cs ================================================ using VirtueSky.Inspector; using VirtueSky.Inspector.Elements; using VirtueSky.Inspector.GroupDrawers; [assembly: RegisterTriGroupDrawer(typeof(TriTabGroupDrawer))] namespace VirtueSky.Inspector.GroupDrawers { public class TriTabGroupDrawer : TriGroupDrawer { public override TriPropertyCollectionBaseElement CreateElement(DeclareTabGroupAttribute attribute) { return new TriTabGroupElement(); } } } ================================================ FILE: VirtueSky/Inspector/Editor.Extras/GroupDrawers/TriTabGroupDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: 2d4f714ffdae47c79edb698ab906daea timeCreated: 1642758980 ================================================ FILE: VirtueSky/Inspector/Editor.Extras/GroupDrawers/TriToggleGroupDrawer.cs ================================================ using VirtueSky.Inspector; using VirtueSky.Inspector.Elements; using VirtueSky.Inspector.GroupDrawers; [assembly: RegisterTriGroupDrawer(typeof(TriToggleGroupDrawer))] namespace VirtueSky.Inspector.GroupDrawers { public class TriToggleGroupDrawer : TriGroupDrawer { public override TriPropertyCollectionBaseElement CreateElement(DeclareToggleGroupAttribute attribute) { return new TriBoxGroupElement(new TriBoxGroupElement.Props { title = attribute.Title, titleMode = TriBoxGroupElement.TitleMode.Toggle, expandedByDefault = attribute.Collapsible, hideIfChildrenInvisible = true, }); } } } ================================================ FILE: VirtueSky/Inspector/Editor.Extras/GroupDrawers/TriToggleGroupDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: cfcf76d363a541e39de3654d978a39ac timeCreated: 1680888338 ================================================ FILE: VirtueSky/Inspector/Editor.Extras/GroupDrawers/TriVerticalGroupDrawer.cs ================================================ using VirtueSky.Inspector; using VirtueSky.Inspector.Elements; using VirtueSky.Inspector.GroupDrawers; [assembly: RegisterTriGroupDrawer(typeof(TriVerticalGroupDrawer))] namespace VirtueSky.Inspector.GroupDrawers { public class TriVerticalGroupDrawer : TriGroupDrawer { public override TriPropertyCollectionBaseElement CreateElement(DeclareVerticalGroupAttribute attribute) { return new TriVerticalGroupElement(); } } } ================================================ FILE: VirtueSky/Inspector/Editor.Extras/GroupDrawers/TriVerticalGroupDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: 20ea0129773b41ea8a2f43a18da811f4 timeCreated: 1643558679 ================================================ FILE: VirtueSky/Inspector/Editor.Extras/GroupDrawers.meta ================================================ fileFormatVersion: 2 guid: f1f781f159fb4215882cf59a6c4cbfa4 timeCreated: 1639417598 ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Processors/DisableIfProcessor.cs ================================================ using VirtueSky.Inspector; using VirtueSky.Inspector.Processors; using VirtueSky.Inspector.Resolvers; [assembly: RegisterTriPropertyDisableProcessor(typeof(DisableIfProcessor))] namespace VirtueSky.Inspector.Processors { public class DisableIfProcessor : TriPropertyDisableProcessor { private ValueResolver _conditionResolver; public override TriExtensionInitializationResult Initialize(TriPropertyDefinition propertyDefinition) { base.Initialize(propertyDefinition); _conditionResolver = ValueResolver.Resolve(propertyDefinition, Attribute.Condition); if (_conditionResolver.TryGetErrorString(out var error)) { return error; } return TriExtensionInitializationResult.Ok; } public sealed override bool IsDisabled(TriProperty property) { var val = _conditionResolver.GetValue(property); var equal = val?.Equals(Attribute.Value) ?? Attribute.Value == null; return equal != Attribute.Inverse; } } } ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Processors/DisableIfProcessor.cs.meta ================================================ fileFormatVersion: 2 guid: d369bf6c40b447ae95d39125ed769582 timeCreated: 1652289896 ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Processors/DisableInEditModeProcessor.cs ================================================ using VirtueSky.Inspector.Processors; using VirtueSky.Inspector; using UnityEngine; [assembly: RegisterTriPropertyDisableProcessor(typeof(DisableInEditModeProcessor))] namespace VirtueSky.Inspector.Processors { public class DisableInEditModeProcessor : TriPropertyDisableProcessor { public override bool IsDisabled(TriProperty property) { return Application.isPlaying == Attribute.Inverse; } } } ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Processors/DisableInEditModeProcessor.cs.meta ================================================ fileFormatVersion: 2 guid: 25cd746f35a64f10805d0983690a10f1 timeCreated: 1642586603 ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Processors/DisableInPlayModeProcessor.cs ================================================ using VirtueSky.Inspector.Processors; using VirtueSky.Inspector; using UnityEngine; [assembly: RegisterTriPropertyDisableProcessor(typeof(DisableInPlayModeProcessor))] namespace VirtueSky.Inspector.Processors { public class DisableInPlayModeProcessor : TriPropertyDisableProcessor { public override bool IsDisabled(TriProperty property) { return Application.isPlaying != Attribute.Inverse; } } } ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Processors/DisableInPlayModeProcessor.cs.meta ================================================ fileFormatVersion: 2 guid: 397dcddedf9a4f91931e5bdc40c668aa timeCreated: 1641385800 ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Processors/HIdeInEditModeProcessor.cs ================================================ using VirtueSky.Inspector.Processors; using VirtueSky.Inspector; using UnityEngine; [assembly: RegisterTriPropertyHideProcessor(typeof(HideInEditModeProcessor))] namespace VirtueSky.Inspector.Processors { public class HideInEditModeProcessor : TriPropertyHideProcessor { public override bool IsHidden(TriProperty property) { return Application.isPlaying == Attribute.Inverse; } } } ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Processors/HIdeInEditModeProcessor.cs.meta ================================================ fileFormatVersion: 2 guid: 1d8995c5efd94e069afca842fc79aab6 timeCreated: 1642586621 ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Processors/HideIfProcessor.cs ================================================ using VirtueSky.Inspector; using VirtueSky.Inspector.Processors; using VirtueSky.Inspector.Resolvers; [assembly: RegisterTriPropertyHideProcessor(typeof(HideIfProcessor))] namespace VirtueSky.Inspector.Processors { public class HideIfProcessor : TriPropertyHideProcessor { private ValueResolver _conditionResolver; public override TriExtensionInitializationResult Initialize(TriPropertyDefinition propertyDefinition) { base.Initialize(propertyDefinition); _conditionResolver = ValueResolver.Resolve(propertyDefinition, Attribute.Condition); if (_conditionResolver.TryGetErrorString(out var error)) { return error; } return TriExtensionInitializationResult.Ok; } public sealed override bool IsHidden(TriProperty property) { var val = _conditionResolver.GetValue(property); var equal = val?.Equals(Attribute.Value) ?? Attribute.Value == null; return equal != Attribute.Inverse; } } } ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Processors/HideIfProcessor.cs.meta ================================================ fileFormatVersion: 2 guid: 141d6b9341384ad58f40cd214c6be095 timeCreated: 1652289316 ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Processors/HideInPlayModeProcessor.cs ================================================ using VirtueSky.Inspector.Processors; using VirtueSky.Inspector; using UnityEngine; [assembly: RegisterTriPropertyHideProcessor(typeof(HideInPlayModeProcessor))] namespace VirtueSky.Inspector.Processors { public class HideInPlayModeProcessor : TriPropertyHideProcessor { public override bool IsHidden(TriProperty property) { return Application.isPlaying != Attribute.Inverse; } } } ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Processors/HideInPlayModeProcessor.cs.meta ================================================ fileFormatVersion: 2 guid: 99642f3dada346b48762044cabacc69e timeCreated: 1641384551 ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Processors.meta ================================================ fileFormatVersion: 2 guid: 3746e0c31b82450b804ea460d753f4fa timeCreated: 1641384540 ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Validators/AssetsOnlyValidator.cs ================================================ using VirtueSky.Inspector; using VirtueSky.Inspector.Validators; using UnityEditor; using UnityEngine; [assembly: RegisterTriAttributeValidator(typeof(AssetsOnlyValidator))] namespace VirtueSky.Inspector.Validators { public class AssetsOnlyValidator : TriAttributeValidator { public override TriExtensionInitializationResult Initialize(TriPropertyDefinition propertyDefinition) { if (!typeof(Object).IsAssignableFrom(propertyDefinition.FieldType)) { return "AssetsOnly attribute can be used only on Object fields"; } return TriExtensionInitializationResult.Ok; } public override TriValidationResult Validate(TriProperty property) { var obj = property.TryGetSerializedProperty(out var serializedProperty) ? serializedProperty.objectReferenceValue : (Object) property.Value; if (obj == null || AssetDatabase.Contains(obj)) { return TriValidationResult.Valid; } return TriValidationResult.Error($"{obj} is not as asset."); } } } ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Validators/AssetsOnlyValidator.cs.meta ================================================ fileFormatVersion: 2 guid: 55b05031f9974136865973d335d322e0 timeCreated: 1654861744 ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Validators/DropdownValidator.cs ================================================ using VirtueSky.Inspector; using VirtueSky.Inspector.Resolvers; using VirtueSky.Inspector.Validators; [assembly: RegisterTriAttributeValidator(typeof(DropdownValidator<>), ApplyOnArrayElement = true)] namespace VirtueSky.Inspector.Validators { public class DropdownValidator : TriAttributeValidator { private DropdownValuesResolver _valuesResolver; public override TriExtensionInitializationResult Initialize(TriPropertyDefinition propertyDefinition) { _valuesResolver = DropdownValuesResolver.Resolve(propertyDefinition, Attribute.Values); if (_valuesResolver.TryGetErrorString(out var error)) { return error; } return TriExtensionInitializationResult.Ok; } public override TriValidationResult Validate(TriProperty property) { foreach (var item in _valuesResolver.GetDropdownItems(property)) { if (property.Comparer.Equals(item.Value, property.Value)) { return TriValidationResult.Valid; } } var msg = $"Dropdown value '{property.Value}' not valid"; switch (Attribute.ValidationMessageType) { case TriMessageType.Info: return TriValidationResult.Info(msg); case TriMessageType.Warning: return TriValidationResult.Warning(msg); case TriMessageType.Error: return TriValidationResult.Error(msg); } return TriValidationResult.Valid; } } } ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Validators/DropdownValidator.cs.meta ================================================ fileFormatVersion: 2 guid: 22bd6d63410f4a7ba8564e185844ddbf timeCreated: 1680714123 ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Validators/InfoBoxValidator.cs ================================================ using VirtueSky.Inspector; using VirtueSky.Inspector.Resolvers; using VirtueSky.Inspector.Validators; [assembly: RegisterTriAttributeValidator(typeof(InfoBoxValidator))] namespace VirtueSky.Inspector.Validators { public class InfoBoxValidator : TriAttributeValidator { private ValueResolver _resolver; private ValueResolver _visibleIfResolver; public override TriExtensionInitializationResult Initialize(TriPropertyDefinition propertyDefinition) { _resolver = ValueResolver.ResolveString(propertyDefinition, Attribute.Text); _visibleIfResolver = Attribute.VisibleIf != null ? ValueResolver.Resolve(propertyDefinition, Attribute.VisibleIf) : null; if (ValueResolver.TryGetErrorString(_resolver, _visibleIfResolver, out var error)) { return error; } return TriExtensionInitializationResult.Ok; } public override TriValidationResult Validate(TriProperty property) { if (_visibleIfResolver != null && !_visibleIfResolver.GetValue(property)) { return TriValidationResult.Valid; } var message = _resolver.GetValue(property, ""); return new TriValidationResult(false, message, Attribute.MessageType); } } } ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Validators/InfoBoxValidator.cs.meta ================================================ fileFormatVersion: 2 guid: d6a852249c1149edbbc1bd0e997726ad timeCreated: 1652968861 ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Validators/MissingReferenceValidator.cs ================================================ using VirtueSky.Inspector; using VirtueSky.Inspector.Validators; using UnityEditor; [assembly: RegisterTriValueValidator(typeof(MissingReferenceValidator))] namespace VirtueSky.Inspector.Validators { public class MissingReferenceValidator : TriValueValidator { public override TriValidationResult Validate(TriValue propertyValue) { if (propertyValue.Property.TryGetSerializedProperty(out var serializedProperty) && serializedProperty.propertyType == SerializedPropertyType.ObjectReference && serializedProperty.objectReferenceValue == null && serializedProperty.objectReferenceInstanceIDValue != 0) { return TriValidationResult.Warning($"{GetName(propertyValue.Property)} is missing"); } return TriValidationResult.Valid; } private static string GetName(TriProperty property) { var name = property.DisplayName; if (string.IsNullOrEmpty(name)) { name = property.RawName; } return name; } } } ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Validators/MissingReferenceValidator.cs.meta ================================================ fileFormatVersion: 2 guid: e6349ecb04a34792bd193b53f6cc0ca3 timeCreated: 1642263604 ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Validators/RequiredValidator.cs ================================================ using JetBrains.Annotations; using VirtueSky.Inspector.Validators; using VirtueSky.Inspector; using VirtueSky.Inspector.Resolvers; [assembly: RegisterTriAttributeValidator(typeof(RequiredValidator), ApplyOnArrayElement = true)] namespace VirtueSky.Inspector.Validators { public class RequiredValidator : TriAttributeValidator { [CanBeNull] private ActionResolver _fixActionResolver; public override TriExtensionInitializationResult Initialize(TriPropertyDefinition propertyDefinition) { if (Attribute.FixAction != null) { _fixActionResolver = ActionResolver.Resolve(propertyDefinition, Attribute.FixAction); } return TriExtensionInitializationResult.Ok; } public override TriValidationResult Validate(TriProperty property) { if (property.FieldType == typeof(string)) { var isNull = string.IsNullOrEmpty((string) property.Value); if (isNull) { var message = Attribute.Message ?? $"{GetName(property)} is required"; return MakeError(message, property); } } else if (typeof(UnityEngine.Object).IsAssignableFrom(property.FieldType)) { var isNull = null == (UnityEngine.Object) property.Value; if (isNull) { var message = Attribute.Message ?? $"{GetName(property)} is required"; return MakeError(message, property); } } else { return TriValidationResult.Error("RequiredAttribute only valid on Object and String"); } return TriValidationResult.Valid; } private TriValidationResult MakeError(string error, TriProperty property) { var result = TriValidationResult.Error(error); if (_fixActionResolver != null) { result = AddFix(result, property); } return result; } private TriValidationResult AddFix(TriValidationResult result, TriProperty property) { return result.WithFix(() => _fixActionResolver?.InvokeForAllTargets(property), Attribute.FixActionName); } private static string GetName(TriProperty property) { var name = property.DisplayName; if (string.IsNullOrEmpty(name)) { name = property.RawName; } return name; } } } ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Validators/RequiredValidator.cs.meta ================================================ fileFormatVersion: 2 guid: 58b713b3023343c3b571cd1b3fa7fdab timeCreated: 1642261781 ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Validators/SceneObjectsOnlyValidator.cs ================================================ using VirtueSky.Inspector; using VirtueSky.Inspector.Validators; using UnityEditor; using UnityEngine; [assembly: RegisterTriAttributeValidator(typeof(SceneObjectsOnlyValidator))] namespace VirtueSky.Inspector.Validators { public class SceneObjectsOnlyValidator : TriAttributeValidator { public override TriExtensionInitializationResult Initialize(TriPropertyDefinition propertyDefinition) { if (!typeof(Object).IsAssignableFrom(propertyDefinition.FieldType)) { return "AssetsOnly attribute can be used only on Object fields"; } return TriExtensionInitializationResult.Ok; } public override TriValidationResult Validate(TriProperty property) { var obj = property.TryGetSerializedProperty(out var serializedProperty) ? serializedProperty.objectReferenceValue : (Object) property.Value; if (obj == null || !AssetDatabase.Contains(obj)) { return TriValidationResult.Valid; } return TriValidationResult.Error($"{obj} cannot be an asset."); } } } ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Validators/SceneObjectsOnlyValidator.cs.meta ================================================ fileFormatVersion: 2 guid: 98948bb92a504f87abeda6e500dc22b2 timeCreated: 1657621306 ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Validators/SceneValidator.cs ================================================ using VirtueSky.Inspector; using VirtueSky.Inspector.Validators; using UnityEditor; [assembly: RegisterTriAttributeValidator(typeof(SceneValidator), ApplyOnArrayElement = true)] namespace VirtueSky.Inspector.Validators { public class SceneValidator : TriAttributeValidator { public override TriValidationResult Validate(TriProperty property) { if (property.FieldType == typeof(string)) { var value = (string) property.Value; if (AssetDatabase.LoadAssetAtPath(value) == null) { return TriValidationResult.Error($"{value} not a valid scene"); } foreach (var scene in EditorBuildSettings.scenes) { if (!property.Comparer.Equals(value, scene.path)) { continue; } if (!scene.enabled) { return TriValidationResult.Error($"{value} disabled in build settings"); } return TriValidationResult.Valid; } return TriValidationResult.Error($"{value} not added to build settings"); } return TriValidationResult.Valid; } } } ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Validators/SceneValidator.cs.meta ================================================ fileFormatVersion: 2 guid: 568b3c97e76048dd8a005d101b86a8e4 timeCreated: 1657958255 ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Validators/TypeMismatchValidator.cs ================================================ using VirtueSky.Inspector; using VirtueSky.Inspector.Validators; using UnityEditor; [assembly: RegisterTriValueValidator(typeof(TypeMismatchValidator<>))] namespace VirtueSky.Inspector.Validators { public class TypeMismatchValidator : TriValueValidator where T : UnityEngine.Object { public override TriValidationResult Validate(TriValue propertyValue) { if (propertyValue.Property.TryGetSerializedProperty(out var serializedProperty) && serializedProperty.propertyType == SerializedPropertyType.ObjectReference && serializedProperty.objectReferenceValue != null && (serializedProperty.objectReferenceValue is T) == false) { var displayName = propertyValue.Property.DisplayName; var actual = serializedProperty.objectReferenceValue.GetType().Name; var expected = propertyValue.Property.FieldType.Name; var msg = $"{displayName} does not match the type: actual = {actual}, expected = {expected}"; return TriValidationResult.Warning(msg); } return TriValidationResult.Valid; } } } ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Validators/TypeMismatchValidator.cs.meta ================================================ fileFormatVersion: 2 guid: 510766d9f1764aae8c21d517ebb2c392 timeCreated: 1652079793 ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Validators/ValidateInputValidator.cs ================================================ using VirtueSky.Inspector; using VirtueSky.Inspector.Resolvers; using VirtueSky.Inspector.Validators; [assembly: RegisterTriAttributeValidator(typeof(ValidateInputValidator))] namespace VirtueSky.Inspector.Validators { public class ValidateInputValidator : TriAttributeValidator { private ValueResolver _resolver; public override TriExtensionInitializationResult Initialize(TriPropertyDefinition propertyDefinition) { base.Initialize(propertyDefinition); _resolver = ValueResolver.Resolve(propertyDefinition, Attribute.Method); if (_resolver.TryGetErrorString(out var error)) { return error; } return TriExtensionInitializationResult.Ok; } public override TriValidationResult Validate(TriProperty property) { if (_resolver.TryGetErrorString(out var error)) { return TriValidationResult.Error(error); } return _resolver.GetValue(property); } } } ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Validators/ValidateInputValidator.cs.meta ================================================ fileFormatVersion: 2 guid: ae1b5ddc1e804ada8a15b6f1501674e0 timeCreated: 1651936935 ================================================ FILE: VirtueSky/Inspector/Editor.Extras/Validators.meta ================================================ fileFormatVersion: 2 guid: e710031376614be5903f943dc4c4d07f timeCreated: 1642261774 ================================================ FILE: VirtueSky/Inspector/Editor.Extras/VirtueSky.Sunflower.Inspector.Editor.Extras.asmdef ================================================ { "name": "VirtueSky.Sunflower.Inspector.Editor.Extras", "rootNamespace": "", "references": [ "Unity.InternalAPIEditorBridge.013", "VirtueSky.Sunflower.Inspector", "VirtueSky.Sunflower.Inspector.Editor" ], "includePlatforms": [ "Editor" ], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": true, "precompiledReferences": [], "autoReferenced": false, "defineConstraints": [], "versionDefines": [], "noEngineReferences": false } ================================================ FILE: VirtueSky/Inspector/Editor.Extras/VirtueSky.Sunflower.Inspector.Editor.Extras.asmdef.meta ================================================ fileFormatVersion: 2 guid: 7be4600869ec09d4ca9a37d1dbfbf1a2 AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Inspector/Editor.Extras.meta ================================================ fileFormatVersion: 2 guid: a7f4b4fc58f88d3459559029b269259e folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Inspector/Editor.meta ================================================ fileFormatVersion: 2 guid: 992bfd855a98c4f45b7f93c37256f4ce folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Buttons/ButtonAttribute.cs ================================================ using System; using System.Diagnostics; namespace VirtueSky.Inspector { [AttributeUsage(AttributeTargets.Method)] [Conditional("UNITY_EDITOR")] public class ButtonAttribute : Attribute { public ButtonAttribute() { } public ButtonAttribute(string name) { Name = name; } public ButtonAttribute(ButtonSizes buttonSize, string name = null) { ButtonSize = (int) buttonSize; Name = name; } public string Name { get; set; } public int ButtonSize { get; } } } ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Buttons/ButtonAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: e51add3a0ba64dc0b53c1e249277055f timeCreated: 1642526402 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Buttons/EnumToggleButtonsAttribute.cs ================================================ using System; using System.Diagnostics; namespace VirtueSky.Inspector { [AttributeUsage((AttributeTargets.Field | AttributeTargets.Property))] [Conditional("UNITY_EDITOR")] public class EnumToggleButtonsAttribute : Attribute { } } ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Buttons/EnumToggleButtonsAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: 59ef9c0c92d344d3936b2f13088dca00 timeCreated: 1653817332 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Buttons.meta ================================================ fileFormatVersion: 2 guid: 51e387526ca64f26b6f86d3126c59ed2 timeCreated: 1758477512 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Collections/ListDrawerSettings.cs ================================================ using System; using System.Diagnostics; namespace VirtueSky.Inspector { [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] [Conditional("UNITY_EDITOR")] public class ListDrawerSettingsAttribute : Attribute { public bool Draggable { get; set; } = true; public bool HideAddButton { get; set; } public bool HideRemoveButton { get; set; } public bool AlwaysExpanded { get; set; } public bool ShowElementLabels { get; set; } public bool ShowDefaultBackground { get; set; } = true; public bool ShowAlternatingBackground { get; set; } = true; } } ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Collections/ListDrawerSettings.cs.meta ================================================ fileFormatVersion: 2 guid: d58dcfa9a4df4af09d44c31a6f74ab26 timeCreated: 1642779136 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Collections/TableListAttribute.cs ================================================ using System; using System.Diagnostics; namespace VirtueSky.Inspector { [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] [Conditional("UNITY_EDITOR")] public class TableListAttribute : ListDrawerSettingsAttribute { } } ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Collections/TableListAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: 45cc7574c4ae44c8946865f3fa2e6ea9 timeCreated: 1642780172 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Collections.meta ================================================ fileFormatVersion: 2 guid: bcdbf1404ef74ed8926926561deddca1 timeCreated: 1758477557 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Conditionals/DisableIfAttribute.cs ================================================ using System; using System.Diagnostics; namespace VirtueSky.Inspector { [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method, AllowMultiple = true)] [Conditional("UNITY_EDITOR")] public class DisableIfAttribute : Attribute { public DisableIfAttribute(string condition) : this(condition, true) { } public DisableIfAttribute(string condition, object value) { Condition = condition; Value = value; } public string Condition { get; } public object Value { get; } public bool Inverse { get; protected set; } } } ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Conditionals/DisableIfAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: 4ec1214049344873acae8035eb78b75f timeCreated: 1652288568 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Conditionals/DisableInEditModeAttribute.cs ================================================ using System; using System.Diagnostics; namespace VirtueSky.Inspector { [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method)] [Conditional("UNITY_EDITOR")] public class DisableInEditModeAttribute : Attribute { public bool Inverse { get; protected set; } } } ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Conditionals/DisableInEditModeAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: d54c241ae2494cb690bf538785a746e6 timeCreated: 1642586566 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Conditionals/DisableInPlayModeAttribute.cs ================================================ using System; using System.Diagnostics; namespace VirtueSky.Inspector { [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method)] [Conditional("UNITY_EDITOR")] public class DisableInPlayModeAttribute : Attribute { public bool Inverse { get; protected set; } } } ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Conditionals/DisableInPlayModeAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: fe853178832f4dde824c372a06a22ae0 timeCreated: 1641385956 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Conditionals/EnableIfAttribute.cs ================================================ using System; using System.Diagnostics; namespace VirtueSky.Inspector { [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method, AllowMultiple = true)] [Conditional("UNITY_EDITOR")] public class EnableIfAttribute : DisableIfAttribute { public EnableIfAttribute(string condition) : this(condition, true) { } public EnableIfAttribute(string condition, object value) : base(condition, value) { Inverse = true; } } } ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Conditionals/EnableIfAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: 41fe52005b34402693769f8acc64b54a timeCreated: 1652288564 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Conditionals/EnableInEditModeAttribute.cs ================================================ using System; using System.Diagnostics; namespace VirtueSky.Inspector { [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method)] [Conditional("UNITY_EDITOR")] public class EnableInEditModeAttribute : DisableInEditModeAttribute { public EnableInEditModeAttribute() { Inverse = true; } } } ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Conditionals/EnableInEditModeAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: bd4e31bd9809431fb5f23d078c28f5ee timeCreated: 1642586583 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Conditionals/EnableInPlayModeAttribute.cs ================================================ using System; using System.Diagnostics; namespace VirtueSky.Inspector { [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method)] [Conditional("UNITY_EDITOR")] public class EnableInPlayModeAttribute : DisableInPlayModeAttribute { public EnableInPlayModeAttribute() { Inverse = true; } } } ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Conditionals/EnableInPlayModeAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: 9dc8b9775fe6475f8d9df0fe00e15c25 timeCreated: 1641385940 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Conditionals/HideIfAttribute.cs ================================================ using System; using System.Diagnostics; namespace VirtueSky.Inspector { [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method, AllowMultiple = true)] [Conditional("UNITY_EDITOR")] public class HideIfAttribute : Attribute { public HideIfAttribute(string condition) : this(condition, true) { } public HideIfAttribute(string condition, object value) { Condition = condition; Value = value; } public string Condition { get; } public object Value { get; } public bool Inverse { get; protected set; } } } ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Conditionals/HideIfAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: 86a795a37ba54419bf857f6044fd6b3e timeCreated: 1652288556 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Conditionals/HideInEditModeAttribute.cs ================================================ using System; using System.Diagnostics; namespace VirtueSky.Inspector { [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method)] [Conditional("UNITY_EDITOR")] public class HideInEditModeAttribute : Attribute { public bool Inverse { get; protected set; } } } ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Conditionals/HideInEditModeAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: e2cd1bf1d1734eb69b9d93d8c5641a64 timeCreated: 1642586553 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Conditionals/HideInPlayModeAttribute.cs ================================================ using System; using System.Diagnostics; namespace VirtueSky.Inspector { [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method)] [Conditional("UNITY_EDITOR")] public class HideInPlayModeAttribute : Attribute { public bool Inverse { get; protected set; } } } ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Conditionals/HideInPlayModeAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: 6686c4df436342e8a75b5ace13a2c590 timeCreated: 1641385927 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Conditionals/ShowIfAttribute.cs ================================================ using System; using System.Diagnostics; namespace VirtueSky.Inspector { [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method, AllowMultiple = true)] [Conditional("UNITY_EDITOR")] public class ShowIfAttribute : HideIfAttribute { public ShowIfAttribute(string condition) : this(condition, true) { } public ShowIfAttribute(string condition, object value) : base(condition, value) { Inverse = true; } } } ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Conditionals/ShowIfAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: 0ff7bd77f2bd4e06be3d07c0f80355d8 timeCreated: 1652288560 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Conditionals/ShowInEditModeAttribute.cs ================================================ using System; using System.Diagnostics; namespace VirtueSky.Inspector { [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method)] [Conditional("UNITY_EDITOR")] public class ShowInEditModeAttribute : HideInEditModeAttribute { public ShowInEditModeAttribute() { Inverse = true; } } } ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Conditionals/ShowInEditModeAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: 21be4e082bd244a6bb7f856c10c7650d timeCreated: 1642586541 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Conditionals/ShowInPlayModeAttribute.cs ================================================ using System; using System.Diagnostics; namespace VirtueSky.Inspector { [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method)] [Conditional("UNITY_EDITOR")] public class ShowInPlayModeAttribute : HideInPlayModeAttribute { public ShowInPlayModeAttribute() { Inverse = true; } } } ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Conditionals/ShowInPlayModeAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: 1129642ac27240c8844f2865f1d38e92 timeCreated: 1641384123 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Conditionals.meta ================================================ fileFormatVersion: 2 guid: bb5a4a51148241f5b791502bf03ca92b timeCreated: 1758477617 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Debug/ShowDrawerChainAttribute.cs ================================================ using System; using System.Diagnostics; namespace VirtueSky.Inspector { [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method)] [Conditional("UNITY_EDITOR")] public class ShowDrawerChainAttribute : Attribute { } } ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Debug/ShowDrawerChainAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: a2856c1dc9ed40ffbe250bf652baf8bb timeCreated: 1638949439 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Debug.meta ================================================ fileFormatVersion: 2 guid: 1aff85796b5f4c6c9485ee91e9714037 timeCreated: 1758477790 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Decorators/DisplayAsStringAttribute.cs ================================================ using System; using System.Diagnostics; namespace VirtueSky.Inspector { [AttributeUsage((AttributeTargets.Field | AttributeTargets.Property))] [Conditional("UNITY_EDITOR")] public class DisplayAsStringAttribute : Attribute { } } ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Decorators/DisplayAsStringAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: ebe54f4dd6f747df9d376712f4aa9c93 timeCreated: 1678604646 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Decorators/DropdownAttribute.cs ================================================ using System; using System.Diagnostics; namespace VirtueSky.Inspector { [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] [Conditional("UNITY_EDITOR")] public class DropdownAttribute : Attribute { public string Values { get; } public TriMessageType ValidationMessageType { get; set; } = TriMessageType.Error; public DropdownAttribute(string values) { Values = values; } } } ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Decorators/DropdownAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: 715d2fca9b1e4330be5d88eddbbdd801 timeCreated: 1656933469 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Decorators/InlineEditorAttribute.cs ================================================ using System; using System.Diagnostics; namespace VirtueSky.Inspector { [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Class | AttributeTargets.Struct)] [Conditional("UNITY_EDITOR")] public class InlineEditorAttribute : Attribute { public InlineEditorModes Mode { get; set; } = InlineEditorModes.GUIOnly; public float PreviewHeight { get; set; } = 50; public InlineEditorAttribute() { } public InlineEditorAttribute(InlineEditorModes mode) { Mode = mode; } } } ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Decorators/InlineEditorAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: 1d09104644014c71b3b0c3b472b743a5 timeCreated: 1641657539 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Decorators/PreviewMeshAttribute.cs ================================================ using System; using System.Diagnostics; namespace VirtueSky.Inspector { [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] [Conditional("UNITY_EDITOR")] public class PreviewMeshAttribute : Attribute { public int Height { get; set; } = 200; public int Width { get; set; } = -1; public bool UseFoldout { get; set; } = true; public PreviewMeshRotationMethod RotationMethod { get; set; } = PreviewMeshRotationMethod.Clamped; public PreviewMeshAttribute() { } public PreviewMeshAttribute(int height) { Height = height; } public PreviewMeshAttribute(int height, int width) { Height = height; Width = width; } public PreviewMeshAttribute(int height, int width, bool useFoldout) { Height = height; Width = width; UseFoldout = useFoldout; } public PreviewMeshAttribute(int height, int width, bool useFoldout, PreviewMeshRotationMethod rotationMethod) { Height = height; Width = width; UseFoldout = useFoldout; RotationMethod = rotationMethod; } } } ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Decorators/PreviewMeshAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: cb7fdcc457c940e591f0ce6683df69bd timeCreated: 1758476479 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Decorators/SceneAttribute.cs ================================================ using System; using System.Diagnostics; namespace VirtueSky.Inspector { [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] [Conditional("UNITY_EDITOR")] public class SceneAttribute : Attribute { } } ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Decorators/SceneAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: aec7c3bafdd64bc9b74b132631a1bcab timeCreated: 1657956550 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Decorators/UnitAttribute.cs ================================================ using System; using System.Diagnostics; namespace VirtueSky.Inspector { [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] [Conditional("UNITY_EDITOR")] public class UnitAttribute : Attribute { public string unitToDisplay; #region Base Units public const string Meter = "m"; public const string Centimeter = "cm"; public const string Millimeter = "mm"; public const string Kilogram = "kg"; public const string Second = "s"; public const string Ampere = "A"; public const string Kelvin = "K"; public const string Mole = "mol"; public const string Candela = "cd"; #endregion #region Derived Units public const string Radian = "rad"; public const string Degree = "°"; public const string Gram = "g"; public const string Liter = "L"; public const string Hertz = "Hz"; public const string Newton = "N"; public const string Pascal = "Pa"; public const string Joule = "J"; public const string Watt = "W"; public const string Coulomb = "C"; public const string Volt = "V"; public const string Ohm = "Ω"; public const string Farad = "F"; public const string Tesla = "T"; public const string Celsius = "°C"; #endregion #region Common Combinations public const string MeterPerSecond = "m/s"; public const string MeterPerSquareSecond = "m/s²"; #endregion #region Extended Physics Units public const string Lux = "lx"; public const string Weber = "Wb"; public const string Sievert = "Sv"; public const string Henry = "H"; public const string Siemens = "S"; public const string Becquerel = "Bq"; public const string Gray = "Gy"; public const string Katal = "kat"; #endregion public UnitAttribute(string unit) { unitToDisplay = unit; } } } ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Decorators/UnitAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: a79b04c7b9824365a3638394d00f1c33 timeCreated: 1758476936 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Decorators.meta ================================================ fileFormatVersion: 2 guid: 0ddbd443c77b4ac289262b901090da8c timeCreated: 1758477832 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Groups/DeclareBoxGroupAttribute.cs ================================================ using System; using System.Diagnostics; namespace VirtueSky.Inspector { [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = true)] [Conditional("UNITY_EDITOR")] public class DeclareBoxGroupAttribute : DeclareGroupBaseAttribute { public DeclareBoxGroupAttribute(string path) : base(path) { Title = path; } public string Title { get; set; } public bool HideTitle { get; set; } } } ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Groups/DeclareBoxGroupAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: 3b8ef8105f574de2b66a434ad3318390 timeCreated: 1639417269 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Groups/DeclareFoldoutGroupAttribute.cs ================================================ using System; using System.Diagnostics; namespace VirtueSky.Inspector { [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = true)] [Conditional("UNITY_EDITOR")] public class DeclareFoldoutGroupAttribute : DeclareGroupBaseAttribute { public DeclareFoldoutGroupAttribute(string path) : base(path) { Title = path; } public string Title { get; set; } public bool Expanded { get; set; } } } ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Groups/DeclareFoldoutGroupAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: 3f930db0458a4705940c19a0df585478 timeCreated: 1668331532 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Groups/DeclareGroupBaseAttribute.cs ================================================ using System; namespace VirtueSky.Inspector { public abstract class DeclareGroupBaseAttribute : Attribute { protected DeclareGroupBaseAttribute(string path) { Path = path ?? "None"; } public string Path { get; } } } ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Groups/DeclareGroupBaseAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: 29196c90aab84065a58211f71c9e280e timeCreated: 1639419849 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Groups/DeclareHorizontalGroupAttribute.cs ================================================ using System; using System.Diagnostics; namespace VirtueSky.Inspector { [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = true)] [Conditional("UNITY_EDITOR")] public class DeclareHorizontalGroupAttribute : DeclareGroupBaseAttribute { public DeclareHorizontalGroupAttribute(string path) : base(path) { } public float[] Sizes { get; set; } } } ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Groups/DeclareHorizontalGroupAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: 9b5d0fa1c34e46bbb34e0ceb78a1e999 timeCreated: 1640871509 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Groups/DeclareTabGroupAttribute.cs ================================================ using System; using System.Diagnostics; namespace VirtueSky.Inspector { [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = true)] [Conditional("UNITY_EDITOR")] public class DeclareTabGroupAttribute : DeclareGroupBaseAttribute { public DeclareTabGroupAttribute(string path) : base(path) { } } } ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Groups/DeclareTabGroupAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: 951a8c6083fe40a69430e6f53d5ba7a0 timeCreated: 1642758819 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Groups/DeclareToggleGroupAttribute.cs ================================================ using System; using System.Diagnostics; namespace VirtueSky.Inspector { [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = true)] [Conditional("UNITY_EDITOR")] public class DeclareToggleGroupAttribute : DeclareGroupBaseAttribute { public DeclareToggleGroupAttribute(string path) : base(path) { Title = path; } public string Title { get; set; } public bool Collapsible { get; set; } = true; } } ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Groups/DeclareToggleGroupAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: f93204143e294161afc85d1c6a3c6d16 timeCreated: 1680887538 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Groups/DeclareVerticalGroupAttribute.cs ================================================ using System; using System.Diagnostics; namespace VirtueSky.Inspector { [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = true)] [Conditional("UNITY_EDITOR")] public class DeclareVerticalGroupAttribute : DeclareGroupBaseAttribute { public DeclareVerticalGroupAttribute(string path) : base(path) { } } } ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Groups/DeclareVerticalGroupAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: f62994cb4c86471aba39b9a0e79ae93a timeCreated: 1643558654 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Groups/GroupAttribute.cs ================================================ using System; using System.Diagnostics; namespace VirtueSky.Inspector { [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method)] [Conditional("UNITY_EDITOR")] public class GroupAttribute : Attribute { public GroupAttribute(string path) { Path = path; } public string Path { get; } } } ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Groups/GroupAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: 34f746736a9e4b8db6093924652cf405 timeCreated: 1639412551 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Groups/GroupNextAttribute.cs ================================================ using System; using System.Diagnostics; using JetBrains.Annotations; namespace VirtueSky.Inspector { [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method)] [Conditional("UNITY_EDITOR")] public class GroupNextAttribute : Attribute { public GroupNextAttribute(string path) { Path = path; } [CanBeNull] public string Path { get; } } [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method)] [Conditional("UNITY_EDITOR")] public class UnGroupNextAttribute : GroupNextAttribute { public UnGroupNextAttribute() : base(null) { } } } ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Groups/GroupNextAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: fb210ae77e66474e92cb101f18052072 timeCreated: 1660802441 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Groups/TabAttribute.cs ================================================ using System; using System.Diagnostics; namespace VirtueSky.Inspector { [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method)] [Conditional("UNITY_EDITOR")] public class TabAttribute : Attribute { public TabAttribute(string tab) { TabName = tab; } public string TabName { get; } } } ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Groups/TabAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: 19d2d001ee784250be738bb1a51a0fc6 timeCreated: 1642758885 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Groups.meta ================================================ fileFormatVersion: 2 guid: 898e22a237174c6284ea59a0a68952ef timeCreated: 1758477958 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Misc/HideMonoScriptAttribute.cs ================================================ using System; using System.Diagnostics; namespace VirtueSky.Inspector { [AttributeUsage((AttributeTargets.Class | AttributeTargets.Struct))] [Conditional("UNITY_EDITOR")] public class HideMonoScriptAttribute : Attribute { } } ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Misc/HideMonoScriptAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: 306721f92da846b5aac744073764a4e2 timeCreated: 1673714382 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Misc/HideReferencePickerAttribute.cs ================================================ using System; namespace VirtueSky.Inspector { [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] public class HideReferencePickerAttribute : Attribute { } } ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Misc/HideReferencePickerAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: d8c607fff5fe44e29891720c2daf2d6e timeCreated: 1659516082 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Misc/OnValueChangedAttribute.cs ================================================ using System; using System.Diagnostics; namespace VirtueSky.Inspector { [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] [Conditional("UNITY_EDITOR")] public class OnValueChangedAttribute : Attribute { public OnValueChangedAttribute(string method) { Method = method; } public string Method { get; } } } ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Misc/OnValueChangedAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: ae1fa081898a4d13b8612da57bc9a349 timeCreated: 1652265504 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Misc/PropertyOrderAttribute.cs ================================================ using System; using System.Diagnostics; namespace VirtueSky.Inspector { [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method)] [Conditional("UNITY_EDITOR")] public class PropertyOrderAttribute : Attribute { public int Order { get; } public PropertyOrderAttribute(int order) { Order = order; } } } ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Misc/PropertyOrderAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: e6de09475a1c44b38ce070f556f5f44d timeCreated: 1638941803 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Misc/ReadOnlyAttribute.cs ================================================ using System; using System.Diagnostics; namespace VirtueSky.Inspector { [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Class | AttributeTargets.Struct)] [Conditional("UNITY_EDITOR")] public class ReadOnlyAttribute : Attribute { } } ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Misc/ReadOnlyAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: 07201e1119294874acfd8417ba34199e timeCreated: 1638885262 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Misc/ShowInInspector.cs ================================================ using System; using System.Diagnostics; namespace VirtueSky.Inspector { [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] [Conditional("UNITY_EDITOR")] public class ShowInInspectorAttribute : Attribute { } } ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Misc/ShowInInspector.cs.meta ================================================ fileFormatVersion: 2 guid: 4d9e5878061041bfa097dda3756bc478 timeCreated: 1639243448 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Misc.meta ================================================ fileFormatVersion: 2 guid: 67a58ebdcdcd4daa970078ef3395d3d2 timeCreated: 1758478036 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Others/DrawWithTriInspectorAttribute.cs ================================================ using System; using System.Diagnostics; namespace VirtueSky.Inspector { [AttributeUsage(AttributeTargets.Class | AttributeTargets.Assembly)] [Conditional("UNITY_EDITOR")] public class DrawWithTriInspectorAttribute : Attribute { } } ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Others/DrawWithTriInspectorAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: 33460afbb365415a9ff9d9379f0cec59 timeCreated: 1652773384 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Others/DrawWithUnityAttribute.cs ================================================ using System; using System.Diagnostics; namespace VirtueSky.Inspector { [AttributeUsage(AttributeTargets.Field)] [Conditional("UNITY_EDITOR")] public class DrawWithUnityAttribute : Attribute { public bool WithUiToolkit { get; set; } } } ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Others/DrawWithUnityAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: 72a4f37291e74452877df4701818e180 timeCreated: 1668181199 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Others.meta ================================================ fileFormatVersion: 2 guid: 685ca44a3b25482c9429f9d1dad382ef timeCreated: 1758478137 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Styling/GUIColorAttribute.cs ================================================ using System; using System.Diagnostics; using UnityEngine; namespace VirtueSky.Inspector { [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Struct)] [Conditional("UNITY_EDITOR")] public class GUIColorAttribute : Attribute { public Color Color { get; } public string GetColor { get; } public GUIColorAttribute(float r, float g, float b, float a = 1f) { Color = new Color(r, g, b, a); } public GUIColorAttribute(byte r, byte g, byte b, byte a = byte.MaxValue) { Color = new Color32(r, g, b, a); } public GUIColorAttribute(string value) { if (value.StartsWith("$")) { GetColor = value; return; } if (ColorUtility.TryParseHtmlString(value, out var color)) { } else if (ColorUtility.TryParseHtmlString($"#{value}", out color)) { } else { color = Color.white; } Color = color; } } } ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Styling/GUIColorAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: e9a20bec5b2a495e9a4035e1585ebfda timeCreated: 1638943497 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Styling/HideLabelAttribute.cs ================================================ using System; using System.Diagnostics; namespace VirtueSky.Inspector { [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] [Conditional("UNITY_EDITOR")] public class HideLabelAttribute : Attribute { } } ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Styling/HideLabelAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: 16ab42968e5c4f86ab9a607cb983508f timeCreated: 1638868812 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Styling/IndentAttribute.cs ================================================ using System; using System.Diagnostics; namespace VirtueSky.Inspector { [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method)] [Conditional("UNITY_EDITOR")] public class IndentAttribute : Attribute { public int Indent { get; } public IndentAttribute() : this(1) { } public IndentAttribute(int indent) { Indent = indent; } } } ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Styling/IndentAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: 0f021bed86024c529a5a265fea051a9f timeCreated: 1638947073 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Styling/InlinePropertyAttribute.cs ================================================ using System; using System.Diagnostics; namespace VirtueSky.Inspector { [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Class | AttributeTargets.Struct)] [Conditional("UNITY_EDITOR")] public class InlinePropertyAttribute : Attribute { public float LabelWidth { get; set; } } } ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Styling/InlinePropertyAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: e788cb72a55a4a69a703dd857b408ace timeCreated: 1638947526 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Styling/LabelTextAttribute.cs ================================================ using System; using System.Diagnostics; namespace VirtueSky.Inspector { [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] [Conditional("UNITY_EDITOR")] public class LabelTextAttribute : Attribute { public string Text { get; } public LabelTextAttribute(string text) { Text = text; } } } ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Styling/LabelTextAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: c7dff14e608f492abd5a4e4c26d4fb5a timeCreated: 1638876608 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Styling/LabelWidthAttribute.cs ================================================ using System; using System.Diagnostics; namespace VirtueSky.Inspector { [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] [Conditional("UNITY_EDITOR")] public class LabelWidthAttribute : Attribute { public float Width { get; } public LabelWidthAttribute(float width) { Width = width; } } } ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Styling/LabelWidthAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: cb503940335041fd804649c32f07ab14 timeCreated: 1638948051 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Styling/PropertySpaceAttribute.cs ================================================ using System; using System.Diagnostics; namespace VirtueSky.Inspector { [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Struct)] [Conditional("UNITY_EDITOR")] public class PropertySpaceAttribute : Attribute { public float SpaceBefore { get; set; } public float SpaceAfter { get; set; } public PropertySpaceAttribute() { SpaceBefore = 7; } public PropertySpaceAttribute(float spaceBefore = 0, float spaceAfter = 0) { SpaceBefore = spaceBefore; SpaceAfter = spaceAfter; } } } ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Styling/PropertySpaceAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: 27a1f5f498a04cc0b7ffedc2d2e6a8ff timeCreated: 1638942425 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Styling/PropertyTooltipAttribute.cs ================================================ using System; using System.Diagnostics; namespace VirtueSky.Inspector { [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] [Conditional("UNITY_EDITOR")] public class PropertyTooltipAttribute : Attribute { public string Tooltip { get; } public PropertyTooltipAttribute(string tooltip) { Tooltip = tooltip; } } } ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Styling/PropertyTooltipAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: a8086d3692f24b48b221ddf74c77bad6 timeCreated: 1638948288 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Styling/TitleAttribute.cs ================================================ using System; using System.Diagnostics; namespace VirtueSky.Inspector { [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method)] [Conditional("UNITY_EDITOR")] public class TitleAttribute : Attribute { public string Title { get; } public bool HorizontalLine { get; set; } = true; public TitleAttribute(string title) { Title = title; } } } ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Styling/TitleAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: 03c62d6e9c5c4b55bd2bf199b9745d95 timeCreated: 1638944189 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Styling.meta ================================================ fileFormatVersion: 2 guid: 53735b40cbf149989d574b93c54a2948 timeCreated: 1758478168 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Validators/AssetsOnlyAttribute.cs ================================================ using System; using System.Diagnostics; namespace VirtueSky.Inspector { [AttributeUsage((AttributeTargets.Field | AttributeTargets.Property))] [Conditional("UNITY_EDITOR")] public class AssetsOnlyAttribute : Attribute { } } ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Validators/AssetsOnlyAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: 0b922aaf25df46a99d356711f341dc06 timeCreated: 1654861722 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Validators/InfoBoxAttribute.cs ================================================ using System; using System.Diagnostics; namespace VirtueSky.Inspector { [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method, AllowMultiple = true)] [Conditional("UNITY_EDITOR")] public class InfoBoxAttribute : Attribute { public string Text { get; } public TriMessageType MessageType { get; } public string VisibleIf { get; } public InfoBoxAttribute(string text, TriMessageType messageType = TriMessageType.Info, string visibleIf = null) { Text = text; MessageType = messageType; VisibleIf = visibleIf; } } } ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Validators/InfoBoxAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: 573a31308ca14b5381aa18ffbff0afe2 timeCreated: 1652897457 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Validators/RequiredAttribute.cs ================================================ using System; namespace VirtueSky.Inspector { [AttributeUsage((AttributeTargets.Field | AttributeTargets.Property))] public class RequiredAttribute : Attribute { public string Message { get; set; } public string FixAction { get; set; } public string FixActionName { get; set; } } } ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Validators/RequiredAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: d886b45ac8b1474db5cdfd07c859e616 timeCreated: 1642261718 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Validators/SceneObjectsOnlyAttribute.cs ================================================ using System; using System.Diagnostics; namespace VirtueSky.Inspector { [AttributeUsage((AttributeTargets.Field | AttributeTargets.Property))] [Conditional("UNITY_EDITOR")] public class SceneObjectsOnlyAttribute : Attribute { } } ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Validators/SceneObjectsOnlyAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: 908b02bc0b5d4cdd88e952625ce0cbc7 timeCreated: 1657621281 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Validators/ValidateInputAttribute.cs ================================================ using System; using System.Diagnostics; namespace VirtueSky.Inspector { [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] [Conditional("UNITY_EDITOR")] public class ValidateInputAttribute : Attribute { public string Method { get; } public ValidateInputAttribute(string method) { Method = method; } } } ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Validators/ValidateInputAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: 0bcc52b28f694396ab43601214283428 timeCreated: 1651936866 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes/Validators.meta ================================================ fileFormatVersion: 2 guid: 69ba815e716e4d92b94c8767f8bea652 timeCreated: 1758478264 ================================================ FILE: VirtueSky/Inspector/Runtime/Attributes.meta ================================================ fileFormatVersion: 2 guid: 2898ff4f810f468ab3ad610520d4305a timeCreated: 1638868804 ================================================ FILE: VirtueSky/Inspector/Runtime/ButtonSizes.cs ================================================ namespace VirtueSky.Inspector { public enum ButtonSizes { Small = 0, Medium = 22, Large = 32, Gigantic = 62, } } ================================================ FILE: VirtueSky/Inspector/Runtime/ButtonSizes.cs.meta ================================================ fileFormatVersion: 2 guid: a7580fa208fd4eb695fa8b9f9ca0c4d7 timeCreated: 1654532890 ================================================ FILE: VirtueSky/Inspector/Runtime/CustomizeAttribute/Attribute/EditorIconAttribute.cs ================================================ using System; using System.Diagnostics; namespace VirtueSky.Inspector { /// /// Specify a texture name from your assets which you want to be assigned as an icon to the MonoScript. /// [AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = false)] [Conditional("UNITY_EDITOR")] public class EditorIconAttribute : System.Attribute { public string Name { get; set; } public EditorIconAttribute(string name) { Name = name; } } } ================================================ FILE: VirtueSky/Inspector/Runtime/CustomizeAttribute/Attribute/EditorIconAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: e2c7ac1f4999450ebc100d2a8b066c9e timeCreated: 1708661065 ================================================ FILE: VirtueSky/Inspector/Runtime/CustomizeAttribute/Attribute/EnumAttribue/ExtendEnumAttribute.cs ================================================ using UnityEngine; namespace VirtueSky.Inspector { [System.AttributeUsage(System.AttributeTargets.Field)] public class ExtendEnumAttribute : PropertyAttribute { public readonly bool display = true; public ExtendEnumAttribute(bool displayValues = true) { display = displayValues; } } } ================================================ FILE: VirtueSky/Inspector/Runtime/CustomizeAttribute/Attribute/EnumAttribue/ExtendEnumAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: 3b2227ae43a24ea4ca175eea402c04fb timeCreated: 1521158383 licenseType: Store MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Inspector/Runtime/CustomizeAttribute/Attribute/EnumAttribue/SearchableEnumAttribute.cs ================================================ using System; using UnityEngine; namespace VirtueSky.Inspector { [AttributeUsage(AttributeTargets.Field)] public class SearchableEnumAttribute : PropertyAttribute { } } ================================================ FILE: VirtueSky/Inspector/Runtime/CustomizeAttribute/Attribute/EnumAttribue/SearchableEnumAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: 3e33b73dbc7248f8887394985c78c798 timeCreated: 1700212218 ================================================ FILE: VirtueSky/Inspector/Runtime/CustomizeAttribute/Attribute/EnumAttribue.meta ================================================ fileFormatVersion: 2 guid: f40063f75ee445bcbae79b16de53f59f timeCreated: 1700212523 ================================================ FILE: VirtueSky/Inspector/Runtime/CustomizeAttribute/Attribute/HeaderLineAttribute.cs ================================================ using System; using UnityEngine; using VirtueSky.Utils; namespace VirtueSky.Inspector { /// /// Display a header with an underline /// [AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = true)] public class HeaderLineAttribute : PropertyAttribute { public readonly string text; public readonly bool isToUpper; public readonly CustomColor colorText; public readonly CustomColor colorLine; //Constructor public HeaderLineAttribute(string text, bool isToUpper = true, CustomColor colorText = CustomColor.LightGray, CustomColor colorLine = CustomColor.LightGray) { this.text = text; this.isToUpper = isToUpper; this.colorText = colorText; this.colorLine = colorLine; } } } ================================================ FILE: VirtueSky/Inspector/Runtime/CustomizeAttribute/Attribute/HeaderLineAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: dbba5ee7a24c4dadbed10d545be73cd9 timeCreated: 1700193284 ================================================ FILE: VirtueSky/Inspector/Runtime/CustomizeAttribute/Attribute/HelpBoxAttribute.cs ================================================ using System.Diagnostics; namespace VirtueSky.Inspector { using System; using UnityEngine; #if UNITY_EDITOR using UnityEditor; [AttributeUsage(AttributeTargets.Field, Inherited = true)] [Conditional("UNITY_EDITOR")] public class HelpBoxAttribute : PropertyAttribute { public readonly string text; // MessageType exists in UnityEditor namespace and can throw an exception when used outside the editor. // We spoof MessageType at the bottom of this script to ensure that errors are not thrown when // MessageType is unavailable. public readonly MessageType type; /// /// Adds a HelpBox to the Unity property inspector above this field. /// /// The help text to be displayed in the HelpBox. /// The icon to be displayed in the HelpBox. public HelpBoxAttribute(string text, MessageType type = MessageType.Info) { this.text = text; this.type = type; } } #endif } ================================================ FILE: VirtueSky/Inspector/Runtime/CustomizeAttribute/Attribute/HelpBoxAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: f511b1121a674d0386cffc689e1ee676 timeCreated: 1700132002 ================================================ FILE: VirtueSky/Inspector/Runtime/CustomizeAttribute/Attribute/HighlightAttribute.cs ================================================ using System; using UnityEngine; using VirtueSky.Utils; namespace VirtueSky.Inspector { [AttributeUsage(AttributeTargets.Field)] public class HighlightAttribute : PropertyAttribute { public CustomColor highColor; public readonly string validateField; public readonly object comparationValue; public readonly object[] comparationValueArray; public HighlightAttribute(CustomColor highColor = CustomColor.Yellow, string validateField = null, object comparationValue = null) { this.highColor = highColor; this.validateField = validateField; this.comparationValue = comparationValue; } } } ================================================ FILE: VirtueSky/Inspector/Runtime/CustomizeAttribute/Attribute/HighlightAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: bc1638a497c24280b2e3fee427ff69bb timeCreated: 1700214606 ================================================ FILE: VirtueSky/Inspector/Runtime/CustomizeAttribute/Attribute/LayerAttribute.cs ================================================ using UnityEngine; namespace VirtueSky.Inspector { public class LayerAttribute : PropertyAttribute { } } ================================================ FILE: VirtueSky/Inspector/Runtime/CustomizeAttribute/Attribute/LayerAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: de8b721c495f43fe94c9d80be3a8f520 timeCreated: 1700035240 ================================================ FILE: VirtueSky/Inspector/Runtime/CustomizeAttribute/Attribute/TagAttribute.cs ================================================ using UnityEngine; namespace VirtueSky.Inspector { public class TagAttribute : PropertyAttribute { } } ================================================ FILE: VirtueSky/Inspector/Runtime/CustomizeAttribute/Attribute/TagAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: 9ad4f47dcc7a426ab9ffc3a190908974 timeCreated: 1700034888 ================================================ FILE: VirtueSky/Inspector/Runtime/CustomizeAttribute/Attribute/TitleColorAttribute.cs ================================================ using UnityEngine; using System; using VirtueSky.Utils; namespace VirtueSky.Inspector { [AttributeUsage(AttributeTargets.Field, Inherited = true)] public class TitleColorAttribute : PropertyAttribute { #region Constants public const float DefaultLineHeight = 1f; public const CustomColor DefaultLineColor = CustomColor.LightGray; public const CustomColor DefaultTitleColor = CustomColor.Bright; #endregion #region Properties public string Title { get; private set; } public float LineHeight { get; private set; } public CustomColor LineColor { get; private set; } public CustomColor TitleColor { get; private set; } public string LineColorString { get; private set; } public string TitleColorString { get; private set; } public float Spacing { get; private set; } public bool AlignTitleLeft { get; private set; } #endregion public TitleColorAttribute(string title = "", CustomColor titleColor = DefaultTitleColor, CustomColor lineColor = DefaultLineColor, float lineHeight = DefaultLineHeight, float spacing = 14f, bool alignTitleLeft = false) { Title = title; TitleColor = titleColor; LineColor = lineColor; TitleColorString = ColorUtility.ToHtmlStringRGB(TitleColor.ToColor()); LineColorString = ColorUtility.ToHtmlStringRGB(LineColor.ToColor()); LineHeight = Mathf.Max(1f, lineHeight); Spacing = spacing; AlignTitleLeft = alignTitleLeft; } } } ================================================ FILE: VirtueSky/Inspector/Runtime/CustomizeAttribute/Attribute/TitleColorAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: 334193c2b3e0480298df5e23f0b8a5ff timeCreated: 1700209198 ================================================ FILE: VirtueSky/Inspector/Runtime/CustomizeAttribute/Attribute.meta ================================================ fileFormatVersion: 2 guid: 4e036ca84be44ff7824644af888aeaab timeCreated: 1700035173 ================================================ FILE: VirtueSky/Inspector/Runtime/CustomizeAttribute/GUIDAttribute.cs ================================================ using UnityEditor; using UnityEngine; using VirtueSky.Utils; namespace VirtueSky.Inspector { public class GUIDAttribute : PropertyAttribute { public string prefix; public GUIDAttribute() { this.prefix = string.Empty; } public GUIDAttribute(string prefix) { this.prefix = prefix; } } #if UNITY_EDITOR [CustomPropertyDrawer(typeof(GUIDAttribute))] public class GuidAttributeDrawer : PropertyDrawer { string Prefix => (attribute as GUIDAttribute).prefix; public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { EditorGUI.BeginProperty(position, label, property); position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label); if (string.IsNullOrEmpty(property.stringValue)) { property.stringValue = Prefix + SimpleMath.NewGuid(); } var w = position.width * 0.3f; position.width = position.width * 0.7f; GUI.enabled = false; EditorGUI.PropertyField(position, property, GUIContent.none); GUI.enabled = true; position.position += new Vector2(position.width, 0); position.width = w; if (GUI.Button(position, new GUIContent("Change"))) { if (!property.serializedObject.isEditingMultipleObjects) property.stringValue = Prefix + SimpleMath.NewGuid(); } property.serializedObject.ApplyModifiedProperties(); EditorGUI.EndProperty(); } } #endif } ================================================ FILE: VirtueSky/Inspector/Runtime/CustomizeAttribute/GUIDAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: af21dbdd68a58c54b9e7cac394dd19f2 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Inspector/Runtime/CustomizeAttribute/NamedIdAttribute.cs ================================================ using System.Text; using UnityEditor; using UnityEngine; #if UNITY_EDITOR using VirtueSky.UtilsEditor; #endif namespace VirtueSky.Inspector { public class NamedIdAttribute : PropertyAttribute { public NamedIdAttribute() { } } #if UNITY_EDITOR [CustomPropertyDrawer(typeof(NamedIdAttribute))] public class NamedIdAttributeDrawer : PropertyDrawer { NamedIdAttribute TargetAttribute => attribute as NamedIdAttribute; public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { EditorGUI.BeginProperty(position, label, property); Context(position, property); position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label); var id = property.stringValue; if (string.IsNullOrEmpty(id)) { id = ToSnakeCase(property.serializedObject.targetObject.name); property.stringValue = id; property.serializedObject.ApplyModifiedProperties(); } using (new EditorGUIUtils.DisabledGUI(true)) { EditorGUI.TextField(position, id); } EditorGUI.EndProperty(); } void Context(Rect rect, SerializedProperty property) { var current = Event.current; if (rect.Contains(current.mousePosition) && current.type == EventType.ContextClick) { var menu = new GenericMenu(); menu.AddItem(new GUIContent("Reset"), false, () => { property.stringValue = ToSnakeCase(property.serializedObject.targetObject.name); property.serializedObject.ApplyModifiedProperties(); }); menu.ShowAsContext(); current.Use(); } } public static string ToSnakeCase(string text) { if (text.Length < 2) { return text; } var sb = new StringBuilder(); sb.Append(char.ToLowerInvariant(text[0])); for (var i = 1; i < text.Length; ++i) { var c = text[i]; if (char.IsUpper(c)) { sb.Append('_'); sb.Append(char.ToLowerInvariant(c)); } else { sb.Append(c); } } return sb.ToString(); } } #endif } ================================================ FILE: VirtueSky/Inspector/Runtime/CustomizeAttribute/NamedIdAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: 14c317c6f93a4a74f8a96614615d0986 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Inspector/Runtime/CustomizeAttribute.meta ================================================ fileFormatVersion: 2 guid: bc2a42be533525d41a7caff1fe74a815 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Inspector/Runtime/InlineEditorModes.cs ================================================ using System; namespace VirtueSky.Inspector { [Flags] public enum InlineEditorModes { GUIOnly = 1 << 0, Header = 1 << 1, Preview = 1 << 2, GUIAndPreview = GUIOnly | Preview, GUIAndHeader = GUIOnly | Header, FullEditor = GUIOnly | Header | Preview, } } ================================================ FILE: VirtueSky/Inspector/Runtime/InlineEditorModes.cs.meta ================================================ fileFormatVersion: 2 guid: f798a09b97da4ed09b5b962c0dbdba0e timeCreated: 1712392526 ================================================ FILE: VirtueSky/Inspector/Runtime/PreviewMeshRotationMethod.cs ================================================ namespace VirtueSky.Inspector { public enum PreviewMeshRotationMethod { Clamped, Freeform, } } ================================================ FILE: VirtueSky/Inspector/Runtime/PreviewMeshRotationMethod.cs.meta ================================================ fileFormatVersion: 2 guid: 5088e59411a34e64b677765b78b045e6 timeCreated: 1758476637 ================================================ FILE: VirtueSky/Inspector/Runtime/TriDropdownList.cs ================================================ using System.Collections.Generic; namespace VirtueSky.Inspector { public class TriDropdownList : List> { public void Add(string text, T value) { Add(new TriDropdownItem {Text = text, Value = value,}); } } public interface ITriDropdownItem { string Text { get; } object Value { get; } } public struct TriDropdownItem : ITriDropdownItem { public string Text { get; set; } public object Value { get; set; } } public struct TriDropdownItem : ITriDropdownItem { public string Text; public T Value; string ITriDropdownItem.Text => Text; object ITriDropdownItem.Value => Value; } } ================================================ FILE: VirtueSky/Inspector/Runtime/TriDropdownList.cs.meta ================================================ fileFormatVersion: 2 guid: bdeda5f861ce4f359c0a25554ffe70bf timeCreated: 1656937692 ================================================ FILE: VirtueSky/Inspector/Runtime/TriValidationResult.cs ================================================ using System; using UnityEngine; namespace VirtueSky.Inspector { public readonly struct TriValidationResult { public static TriValidationResult Valid => new TriValidationResult(true, null, TriMessageType.None); public TriValidationResult(bool valid, string message, TriMessageType messageType, Action fixAction = null, GUIContent fixActionContent = null) { IsValid = valid; Message = message; MessageType = messageType; FixAction = fixAction; FixActionContent = fixActionContent; } public bool IsValid { get; } public string Message { get; } public TriMessageType MessageType { get; } public Action FixAction { get; } public GUIContent FixActionContent { get; } public TriValidationResult WithFix(Action action, string name = null) { return new TriValidationResult(IsValid, Message, MessageType, action, new GUIContent(name ?? "Fix")); } public static TriValidationResult Info(string error) { return new TriValidationResult(false, error, TriMessageType.Info); } public static TriValidationResult Error(string error) { return new TriValidationResult(false, error, TriMessageType.Error); } public static TriValidationResult Warning(string error) { return new TriValidationResult(false, error, TriMessageType.Warning); } } public enum TriMessageType { None, Info, Warning, Error, } } ================================================ FILE: VirtueSky/Inspector/Runtime/TriValidationResult.cs.meta ================================================ fileFormatVersion: 2 guid: 428f8881a0d34edf8148591af6f9a0e7 timeCreated: 1642525992 ================================================ FILE: VirtueSky/Inspector/Runtime/VirtueSky.Sunflower.Inspector.asmdef ================================================ { "name": "VirtueSky.Sunflower.Inspector", "rootNamespace": "", "references": [ "GUID:c282fd4f3fc2c7540914e85842a013c7", "GUID:c904f6d969e991d459a0843b71c22ec5" ], "includePlatforms": [], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": true, "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], "versionDefines": [], "noEngineReferences": false } ================================================ FILE: VirtueSky/Inspector/Runtime/VirtueSky.Sunflower.Inspector.asmdef.meta ================================================ fileFormatVersion: 2 guid: 324caed91501a9c47a04ebfd87b68794 AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Inspector/Runtime.meta ================================================ fileFormatVersion: 2 guid: 2e0eb7988fa380c4c90c94d3ba0a282f folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Inspector/Unity.InternalAPIEditorBridge.012/AdvancedDropdownProxy.cs ================================================ using UnityEditor.IMGUI.Controls; namespace VirtueSky.InspectorUnityInternalBridge { public class AdvancedDropdownProxy { public static void SetShowHeader(AdvancedDropdown dropdown, bool showHeader) { dropdown.m_WindowInstance.showHeader = showHeader; } } } ================================================ FILE: VirtueSky/Inspector/Unity.InternalAPIEditorBridge.012/AdvancedDropdownProxy.cs.meta ================================================ fileFormatVersion: 2 guid: fbe08837c89a44e29ea221ffeadb811d timeCreated: 1652084409 ================================================ FILE: VirtueSky/Inspector/Unity.InternalAPIEditorBridge.012/AssemblyInfo.cs ================================================ using System.Runtime.CompilerServices; [assembly: InternalsVisibleTo("TriInspector.Editor")] [assembly: InternalsVisibleTo("TriInspector.Editor.Extras")] ================================================ FILE: VirtueSky/Inspector/Unity.InternalAPIEditorBridge.012/AssemblyInfo.cs.meta ================================================ fileFormatVersion: 2 guid: ceaac34ef4d54edea2f5bd49bc1145a5 timeCreated: 1652008241 ================================================ FILE: VirtueSky/Inspector/Unity.InternalAPIEditorBridge.012/EditorGUIUtilityProxy.cs ================================================ using UnityEditor; using UnityEngine; namespace VirtueSky.InspectorUnityInternalBridge { public static class EditorGUIUtilityProxy { public static Texture2D GetHelpIcon(MessageType type) { return EditorGUIUtility.GetHelpIcon(type); } } } ================================================ FILE: VirtueSky/Inspector/Unity.InternalAPIEditorBridge.012/EditorGUIUtilityProxy.cs.meta ================================================ fileFormatVersion: 2 guid: 0c34c0be768944a3ad89255c85434802 timeCreated: 1641381655 ================================================ FILE: VirtueSky/Inspector/Unity.InternalAPIEditorBridge.012/EditorProxy.cs ================================================ using UnityEditor; namespace VirtueSky.InspectorUnityInternalBridge { public static class EditorProxy { public static void DoDrawDefaultInspector(SerializedObject obj) { Editor.DoDrawDefaultInspector(obj); } } } ================================================ FILE: VirtueSky/Inspector/Unity.InternalAPIEditorBridge.012/EditorProxy.cs.meta ================================================ fileFormatVersion: 2 guid: 993f9dfd66614ba68fcf95c0e7e098e3 timeCreated: 1683783433 ================================================ FILE: VirtueSky/Inspector/Unity.InternalAPIEditorBridge.012/GUIClipProxy.cs ================================================ using System; using System.Reflection; using UnityEditor; using UnityEngine; namespace VirtueSky.InspectorUnityInternalBridge { public static class GUIClipProxy { private static Func _guiClipUnClipVector2; private static Func _guiClipUnClipToWindowRect; private static Func _guiClipVisibleRect; [InitializeOnLoadMethod] private static void Setup() { var imGuiModuleAssembly = typeof(GUI).Assembly; var guiClipType = imGuiModuleAssembly.GetType("UnityEngine.GUIClip", throwOnError: true); _guiClipUnClipVector2 = (Func) Delegate.CreateDelegate(typeof(Func), guiClipType.GetMethod("Unclip", new[] {typeof(Vector2)})); _guiClipUnClipToWindowRect = (Func) Delegate.CreateDelegate(typeof(Func), guiClipType.GetMethod("UnclipToWindow", new[] {typeof(Rect)})); _guiClipVisibleRect = (Func) Delegate.CreateDelegate(typeof(Func), guiClipType.GetProperty("visibleRect", BindingFlags.Static | BindingFlags.NonPublic).GetMethod); } public static Rect VisibleRect => _guiClipVisibleRect.Invoke(); public static Vector2 UnClip(Vector2 pos) { return _guiClipUnClipVector2.Invoke(pos); } public static Rect UnClipToWindow(Rect rect) { return _guiClipUnClipToWindowRect.Invoke(rect); } } } ================================================ FILE: VirtueSky/Inspector/Unity.InternalAPIEditorBridge.012/GUIClipProxy.cs.meta ================================================ fileFormatVersion: 2 guid: e573403f6f844648ab1dc4013c8c4856 timeCreated: 1690734495 ================================================ FILE: VirtueSky/Inspector/Unity.InternalAPIEditorBridge.012/InternalEditorUtilityProxy.cs ================================================ using UnityEditorInternal; namespace VirtueSky.InspectorUnityInternalBridge { public static class InternalEditorUtilityProxy { public static bool GetIsInspectorExpanded(UnityEngine.Object obj) { return InternalEditorUtility.GetIsInspectorExpanded(obj); } public static void SetIsInspectorExpanded(UnityEngine.Object obj, bool isExpanded) { InternalEditorUtility.SetIsInspectorExpanded(obj, isExpanded); } } } ================================================ FILE: VirtueSky/Inspector/Unity.InternalAPIEditorBridge.012/InternalEditorUtilityProxy.cs.meta ================================================ fileFormatVersion: 2 guid: c25961327a574e9399f5ebc2d9a929ea timeCreated: 1642757678 ================================================ FILE: VirtueSky/Inspector/Unity.InternalAPIEditorBridge.012/ReorderableListProxy.cs ================================================ using System; using System.Reflection; using UnityEditorInternal; using UnityEngine; using Object = UnityEngine.Object; namespace VirtueSky.InspectorUnityInternalBridge { public static class ReorderableListProxy { #if !UNITY_2021_3_OR_NEWER private static readonly MethodInfo ClearCacheMethod; #endif private static ReorderableList.Defaults _defaultBehaviours; // ReSharper disable once InconsistentNaming public static ReorderableList.Defaults defaultBehaviours { get { if (_defaultBehaviours == null) { _defaultBehaviours = new ReorderableList.Defaults(); } return _defaultBehaviours; } } static ReorderableListProxy() { #if !UNITY_2021_3_OR_NEWER const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; ClearCacheMethod = typeof(ReorderableList).GetMethod("InvalidateCacheRecursive", flags) ?? typeof(ReorderableList).GetMethod("ClearCacheRecursive", flags); #endif } public static void DoListHeader(ReorderableList list, Rect headerRect) { if (list.showDefaultBackground && Event.current.type == EventType.Repaint) { defaultBehaviours.DrawHeaderBackground(headerRect); } headerRect.xMin += 6f; headerRect.xMax -= 6f; headerRect.height -= 2f; headerRect.y += 1; list.drawHeaderCallback?.Invoke(headerRect); } public static void ClearCacheRecursive(ReorderableList list) { #if UNITY_2021_3_OR_NEWER list.InvalidateCacheRecursive(); #else ClearCacheMethod?.Invoke(list, Array.Empty()); #endif } public static void DoAddButton(ReorderableList list, Object value) { #if UNITY_2020_2_OR_NEWER defaultBehaviours.DoAddButton(list, value); #else defaultBehaviours.DoAddButton(list); #endif } } } ================================================ FILE: VirtueSky/Inspector/Unity.InternalAPIEditorBridge.012/ReorderableListProxy.cs.meta ================================================ fileFormatVersion: 2 guid: acf8923868a81dd41825ea3ce86c0455 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Inspector/Unity.InternalAPIEditorBridge.012/ScriptAttributeUtilityProxy.cs ================================================ using UnityEditor; using UnityEngine; using UnityEngine.UIElements; namespace VirtueSky.InspectorUnityInternalBridge { public static class ScriptAttributeUtilityProxy { public static PropertyHandlerProxy GetHandler(SerializedProperty property) { var handler = ScriptAttributeUtility.GetHandler(property); return new PropertyHandlerProxy(handler); } } public readonly struct PropertyHandlerProxy { private readonly PropertyHandler _handler; internal PropertyHandlerProxy(PropertyHandler handler) { _handler = handler; } // ReSharper disable once InconsistentNaming public bool hasPropertyDrawer => _handler.hasPropertyDrawer; public void SetPreferredLabel(string label) { #if UNITY_2022_2_OR_NEWER if (_handler.propertyDrawer != null) { _handler.propertyDrawer.m_PreferredLabel = label; } #endif } public VisualElement CreatePropertyGUI(SerializedProperty property) { return _handler.propertyDrawer?.CreatePropertyGUI(property); } public float GetHeight(SerializedProperty property, GUIContent label, bool includeChildren) { return _handler.GetHeight(property, label, includeChildren); } public bool OnGUI(Rect position, SerializedProperty property, GUIContent label, bool includeChildren) { return _handler.OnGUI(position, property, label, includeChildren); } } } ================================================ FILE: VirtueSky/Inspector/Unity.InternalAPIEditorBridge.012/ScriptAttributeUtilityProxy.cs.meta ================================================ fileFormatVersion: 2 guid: 9d3310787ea648a18e32a0da39a292c2 timeCreated: 1638773139 ================================================ FILE: VirtueSky/Inspector/Unity.InternalAPIEditorBridge.012/Unity.InternalAPIEditorBridge.013.asmdef ================================================ { "name": "Unity.InternalAPIEditorBridge.013", "rootNamespace": "", "references": [], "includePlatforms": [ "Editor" ], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], "versionDefines": [], "noEngineReferences": false } ================================================ FILE: VirtueSky/Inspector/Unity.InternalAPIEditorBridge.012/Unity.InternalAPIEditorBridge.013.asmdef.meta ================================================ fileFormatVersion: 2 guid: 710c5eba4cfb6804d9772afbcd0a22eb AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Inspector/Unity.InternalAPIEditorBridge.012.meta ================================================ fileFormatVersion: 2 guid: 17812d8658d186345af6f2e6bbc1c31b folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Inspector/Version.txt ================================================ Tri-Inspector: v1.15.1 ================================================ FILE: VirtueSky/Inspector/Version.txt.meta ================================================ fileFormatVersion: 2 guid: e662fde09058f4642a2a955bc82ab382 TextScriptImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Inspector.meta ================================================ fileFormatVersion: 2 guid: 1e11cadef476da9428eeb37c6e6a03c7 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/LevelEditor/LevelEditor.cs ================================================ using System; using System.Collections.Generic; using System.IO; using System.Linq; using UnityEditor; using UnityEditor.SceneManagement; using UnityEngine; using VirtueSky.Inspector; using VirtueSky.Misc; using VirtueSky.UtilsEditor; namespace VirtueSky.LevelEditor { public class LevelEditor : EditorWindow { // private class PickObject // { // public string group; // public GameObject pickedObject; // } // #region preview generator // // private static PreviewGenerator previewGenerator; // // private static PreviewGenerator PreviewGenerator // { // get // { // var generator = previewGenerator; // if (generator != null) return generator; // // return previewGenerator = new PreviewGenerator // { // width = 512, height = 512, transparentBackground = true, // sizingType = PreviewGenerator.ImageSizeType.Fit // }; // } // } // // private static Dictionary previewDict; // // public static void ClearPreviews() // { // if (previewDict != null) // { // foreach (var kvp in previewDict.ToList()) // { // previewDict[kvp.Key] = null; // } // // previewDict.Clear(); // } // } // // public static void ClearPreview(GameObject go) // { // if (previewDict?.TryGetValue(go, out var tex) ?? false) // { // UnityEngine.Object.DestroyImmediate(tex); // previewDict.Remove(go); // } // } // // public static Texture2D GetPreview(GameObject go, bool canCreate = true) // { // if (!go) return null; // previewDict ??= new Dictionary(); // previewDict.TryGetValue(go, out var tex); // if (!canCreate) return tex != null ? tex : default; // // if (tex) return tex; // tex = PreviewGenerator.CreatePreview(go.gameObject); // previewDict[go] = tex; // // return tex; // } // // #endregion // // // private readonly string[] _optionsSpawn = { "Default", "Index", "Custom" }; // private readonly string[] _optionsMode = { "Renderer", "Ignore" }; // // private Vector2 _pickObjectScrollPosition; // private Vector2 _whiteScrollPosition; // private Vector2 _blackScrollPosition; // private PickObject _currentPickObject; // private List _pickObjects; // private SerializedObject _pathFolderSerializedObject; // private SerializedProperty _pathFolderProperty; // private int _selectedSpawn; // private int _selectedMode; // private GameObject _rootSpawn; // private int _rootIndexSpawn; // private GameObject _previewPickupObject; // private UnityEngine.Object _previousObjectInpectorPreview; // private UnityEditor.Editor _editorInpsectorPreview; // // private static Vector2 EventMousePoint // { // get // { // var position = Event.current.mousePosition; // position.y = Screen.height - position.y - 60f; // return position; // } // } // // private List PickObjects => _pickObjects ??= new List(); // // // private void OnEnable() // { // RefreshPickObject(); // SceneView.duringSceneGui += OnSceneGUI; // } // // private void OnDisable() // { // SceneView.duringSceneGui -= OnSceneGUI; // } // // // private void OnProjectChange() // { // TryClose(); // } // // private void OnHierarchyChange() // { // TryClose(); // } // // private bool TryClose() // { // return false; // } // // // ReSharper disable once UnusedMember.Local // private void RefreshAll() // { // LevelEditor.ClearPreviews(); // RefreshPickObject(); // ClearEditor(); // } // // /// // /// display picked object in editor // /// // private void RefreshPickObject() // { // _pickObjects = new List(); // var blacklistAssets = new List(); // var whitelistAssets = new List(); // if (!LevelSystemEditorSetting.Instance.blacklistPaths.IsNullOrEmpty()) // { // blacklistAssets = AssetDatabase.FindAssets("t:GameObject", // LevelSystemEditorSetting.Instance.blacklistPaths.ToArray()) // .Select(AssetDatabase.GUIDToAssetPath) // .Select(AssetDatabase.LoadAssetAtPath) // .ToList(); // // foreach (string blacklistPath in LevelSystemEditorSetting.Instance.blacklistPaths) // { // if (File.Exists(blacklistPath)) // blacklistAssets.Add( // AssetDatabase.LoadAssetAtPath(blacklistPath)); // } // } // // if (!LevelSystemEditorSetting.Instance.whitelistPaths.IsNullOrEmpty()) // { // whitelistAssets = AssetDatabase.FindAssets("t:GameObject", // LevelSystemEditorSetting.Instance.whitelistPaths.ToArray()) // .Select(AssetDatabase.GUIDToAssetPath) // .Select(AssetDatabase.LoadAssetAtPath) // .ToList(); // // foreach (string whitelistPath in LevelSystemEditorSetting.Instance.whitelistPaths) // { // if (File.Exists(whitelistPath)) // whitelistAssets.Add( // AssetDatabase.LoadAssetAtPath(whitelistPath)); // } // } // // var resultAssets = whitelistAssets.Where(_ => !blacklistAssets.Contains(_)); // foreach (var o in resultAssets) // { // string group = Path.GetDirectoryName(AssetDatabase.GetAssetPath(o)) // ?.Replace('\\', '/').Split('/').Last(); // var po = new PickObject { pickedObject = o.gameObject, group = group }; // _pickObjects.Add(po); // } // } // // private bool CheckEscape() // { // if (Event.current.type == EventType.KeyDown && Event.current.keyCode == KeyCode.Escape) // { // _currentPickObject = null; // Repaint(); // SceneView.RepaintAll(); // return true; // } // // return false; // } // // private void OnGUI() // { // EditorGUI.DrawRect(new Rect(0, 0, position.width, position.height), // GameDataEditor.ColorBackgroundRectWindowSunflower.ToColor()); // GUI.contentColor = GameDataEditor.ColorTextContentWindowSunflower.ToColor(); // GUI.backgroundColor = GameDataEditor.ColorContentWindowSunflower.ToColor(); // GUILayout.Space(8); // if (TryClose()) return; // if (CheckEscape()) return; // SceneView.RepaintAll(); // InternalDrawDropArea(); // GUILayout.Space(4); // InternalDrawSetting(); // GUILayout.Space(4); // InternalDrawPickupArea(); // } // // private void InternalDrawDropArea() // { // Uniform.DrawGroupFoldout("level_editor_drop_area", "Drop Area", DrawDropArea, false); // // void DrawDropArea() // { // GUILayout.Space(2); // float width = 0; // var @event = Event.current; // // #region horizontal // // EditorGUILayout.BeginHorizontal(); // var whiteArea = GUILayoutUtility.GetRect(0.0f, 50f, GUILayout.ExpandWidth(true)); // var blackArea = GUILayoutUtility.GetRect(0.0f, 50f, GUILayout.ExpandWidth(true)); // // ReSharper disable once CompareOfFloatsByEqualityOperator // if (whiteArea.width == 1f) width = position.width / 2; // else width = whiteArea.width; // GUI.backgroundColor = new Color(0f, 0.83f, 1f); // GUI.Box(whiteArea, "[WHITE LIST]", // new GUIStyle(EditorStyles.helpBox) // { alignment = TextAnchor.MiddleCenter, fontStyle = FontStyle.Italic }); // GUI.backgroundColor = Color.white; // GUI.backgroundColor = new Color(1f, 0.13f, 0f); // GUI.Box(blackArea, "[BLACK LIST]", // new GUIStyle(EditorStyles.helpBox) // { alignment = TextAnchor.MiddleCenter, fontStyle = FontStyle.Italic }); // GUI.backgroundColor = Color.white; // switch (@event.type) // { // case EventType.DragUpdated: // case EventType.DragPerform: // if (whiteArea.Contains(@event.mousePosition)) // { // DragAndDrop.visualMode = DragAndDropVisualMode.Copy; // if (@event.type == EventType.DragPerform) // { // DragAndDrop.AcceptDrag(); // foreach (string path in DragAndDrop.paths) // { // if (File.Exists(path)) // { // var r = AssetDatabase.LoadAssetAtPath( // path); // if (r.GetType() != typeof(GameObject)) continue; // } // // ValidateWhitelist(path, // ref LevelSystemEditorSetting.Instance.blacklistPaths); // AddToWhitelist(path); // } // // ReduceScopeDirectory(ref LevelSystemEditorSetting.Instance // .whitelistPaths); // RefreshAll(); // } // } // else if (blackArea.Contains(@event.mousePosition)) // { // DragAndDrop.visualMode = DragAndDropVisualMode.Copy; // if (@event.type == EventType.DragPerform) // { // DragAndDrop.AcceptDrag(); // foreach (string path in DragAndDrop.paths) // { // if (File.Exists(path)) // { // var r = AssetDatabase.LoadAssetAtPath( // path); // if (r.GetType() != typeof(GameObject)) continue; // } // // ValidateBlacklist(path, // ref LevelSystemEditorSetting.Instance.whitelistPaths); // AddToBlacklist(path); // } // // ReduceScopeDirectory(ref LevelSystemEditorSetting.Instance // .blacklistPaths); // RefreshAll(); // } // } // // break; // case EventType.MouseDown when @event.button == 1: // var menu = new GenericMenu(); // if (whiteArea.Contains(@event.mousePosition)) // { // menu.AddItem(new GUIContent("Clear All [WHITE LIST]"), // false, // () => // { // LevelSystemEditorSetting.Instance.whitelistPaths.Clear(); // SaveLevelSystemSetting(); // RefreshAll(); // }); // } // else if (blackArea.Contains(@event.mousePosition)) // { // menu.AddItem(new GUIContent("Clear All [BLACK LIST]"), // false, // () => // { // LevelSystemEditorSetting.Instance.blacklistPaths.Clear(); // SaveLevelSystemSetting(); // RefreshAll(); // }); // } // // menu.ShowAsContext(); // break; // } // // EditorGUILayout.EndHorizontal(); // // #endregion // // // #region horizontal // // EditorGUILayout.BeginHorizontal(); // // #region vertical scope // // using (var scope = new EditorGUILayout.VerticalScope(GUILayout.Width(width - 10))) // { // if (LevelSystemEditorSetting.Instance.whitelistPaths.Count == 0) // { // EditorGUILayout.LabelField(new GUIContent(""), GUILayout.Width(width - 50), // GUILayout.Height(0)); // } // else // { // GUILayout.Space(2); // _whiteScrollPosition = GUILayout.BeginScrollView(_whiteScrollPosition, // false, false, GUILayout.Height(250)); // foreach (string t in LevelSystemEditorSetting.Instance.whitelistPaths // .ToList()) // { // DrawRow(t, // width, // _ => // { // LevelSystemEditorSetting.Instance.whitelistPaths.Remove(_); // SaveLevelSystemSetting(); // }); // } // // GUILayout.EndScrollView(); // } // } // // #endregion // // // GUILayout.Space(4); // // #region vertical scope // // using (var scope = new EditorGUILayout.VerticalScope(GUILayout.Width(width - 15))) // { // if (LevelSystemEditorSetting.Instance.blacklistPaths.Count == 0) // { // EditorGUILayout.LabelField(new GUIContent(""), GUILayout.Width(width - 50), // GUILayout.Height(0)); // } // else // { // GUILayout.Space(2); // _blackScrollPosition = GUILayout.BeginScrollView(_blackScrollPosition, // false, false, GUILayout.Height(250)); // foreach (string t in LevelSystemEditorSetting.Instance.blacklistPaths // .ToList()) // { // DrawRow(t, // width, // _ => // { // LevelSystemEditorSetting.Instance.blacklistPaths.Remove(_); // SaveLevelSystemSetting(); // }); // } // // GUILayout.EndScrollView(); // } // } // // #endregion // // // EditorGUILayout.EndHorizontal(); // // #endregion // } // // void DrawRow(string content, float width, Action action) // { // #region horizontal // // EditorGUILayout.BeginHorizontal(); // EditorGUILayout.LabelField(new GUIContent(content), GUILayout.Width(width - 100)); // GUILayout.FlexibleSpace(); // if (GUILayout.Button(Uniform.IconContent("d_scenevis_visible_hover", // "Ping Selection"))) // { // var obj = AssetDatabase.LoadAssetAtPath(content); // Selection.activeObject = obj; // EditorGUIUtility.PingObject(obj); // } // // if (GUILayout.Button(Uniform.IconContent("Toolbar Minus", "Remove"))) // { // action?.Invoke(content); // RefreshAll(); // } // // EditorGUILayout.EndHorizontal(); // // #endregion // } // } // // private void ValidateWhitelist(string path, ref List blackList) // { // foreach (string t in blackList.ToList()) // { // if (path.Equals(t)) blackList.Remove(t); // } // } // // private void ValidateBlacklist(string path, ref List whiteList) // { // foreach (string t in whiteList.ToList()) // { // if (path.Equals(t) || IsChildOfPath(t, path)) whiteList.Remove(t); // } // } // // private void AddToWhitelist(string path) // { // var check = false; // foreach (string whitePath in LevelSystemEditorSetting.Instance.whitelistPaths) // { // if (IsChildOfPath(path, whitePath)) check = true; // } // // if (!check) LevelSystemEditorSetting.Instance.whitelistPaths.Add(path); // LevelSystemEditorSetting.Instance.whitelistPaths = LevelSystemEditorSetting.Instance // .whitelistPaths.Distinct().ToList(); //unique // SaveLevelSystemSetting(); // } // // private void AddToBlacklist(string path) // { // var check = false; // foreach (string blackPath in LevelSystemEditorSetting.Instance.blacklistPaths) // { // if (IsChildOfPath(path, blackPath)) check = true; // } // // if (!check) LevelSystemEditorSetting.Instance.blacklistPaths.Add(path); // LevelSystemEditorSetting.Instance.blacklistPaths = LevelSystemEditorSetting.Instance // .blacklistPaths.Distinct().ToList(); //unique // SaveLevelSystemSetting(); // } // // // return true if child is childrent of parent // private bool IsChildOfPath(string child, string parent) // { // if (child.Equals(parent)) return false; // var allParent = new List(); // GetAllParentDirectories(new DirectoryInfo(child), ref allParent); // // foreach (var p in allParent) // { // bool check = EqualPath(p, parent); // if (check) return true; // } // // return false; // } // // private void GetAllParentDirectories(DirectoryInfo directoryToScan, // ref List directories) // { // while (true) // { // if (directoryToScan == null || directoryToScan.Name == directoryToScan.Root.Name || // !directoryToScan.FullName.Contains("Assets")) return; // // directories.Add(directoryToScan); // directoryToScan = directoryToScan.Parent; // } // } // // private bool EqualPath(FileSystemInfo info, string str) // { // string relativePath = info.FullName; // if (relativePath.StartsWith(Application.dataPath.Replace('/', '\\'))) // relativePath = "Assets" + relativePath.Substring(Application.dataPath.Length); // relativePath = relativePath.Replace('\\', '/'); // return str.Equals(relativePath); // } // // private void ReduceScopeDirectory(ref List source) // { // var arr = new string[source.Count]; // source.CopyTo(arr); // var valueRemove = new List(); // var unique = arr.Distinct().ToList(); // foreach (string u in unique) // { // var check = false; // foreach (string k in unique) // { // if (IsChildOfPath(u, k)) check = true; // } // // if (check) valueRemove.Add(u); // } // // foreach (string i in valueRemove) // { // unique.Remove(i); // } // // source = unique; // } // // private void InternalDrawSetting() // { // Uniform.DrawGroupFoldout("level_editor_config", "Setting", DrawSetting); // // void DrawSetting() // { // _selectedSpawn = // EditorGUILayout.Popup("Where Spawn", _selectedSpawn, _optionsSpawn); // if (EditorGUI.EndChangeCheck()) // { // switch (_optionsSpawn[_selectedSpawn].ToLower()) // { // case "default": // break; // case "index": // var currentPrefabState = GetCurrentPrefabStage(); // if (currentPrefabState != null) // { // _rootIndexSpawn = EditorGUILayout.IntField( // new GUIContent("Index spawn", "Index from root stage contex"), // _rootIndexSpawn); // } // else // { // EditorGUILayout.HelpBox("Index spawn only work in PrefabMode!", // MessageType.Warning); // } // // break; // case "custom": // _rootSpawn = (GameObject)EditorGUILayout.ObjectField( // "Spawn in GO here -->", _rootSpawn, typeof(GameObject), true); // break; // } // } // // _selectedMode = EditorGUILayout.Popup("Mode", _selectedMode, _optionsMode); // if (EditorGUI.EndChangeCheck()) // { // switch (_optionsMode[_selectedMode].ToLower()) // { // case "renderer": // EditorGUILayout.HelpBox("Based on Renderer detection", // MessageType.Info); // break; // case "ignore": // EditorGUILayout.HelpBox( // "GameObject will be spawn correcty at raycast location\nIgnore calculate bound object", // MessageType.Info); // break; // } // } // } // } // // private void InternalDrawPickupArea() // { // float height = 0f; // Uniform.DrawGroupFoldoutWithRightClick("level_editor_pickup_area", "Pickup Area", // DrawPickupArea, ShowMenuRefresh); // // void DrawPickupArea() // { // var tex = LevelEditor.GetPreview(_currentPickObject?.pickedObject); // if (tex) // { // string pickObjectName = _currentPickObject?.pickedObject.name; // // #region horizontal // // EditorGUILayout.BeginHorizontal(); // GUILayout.Space(position.width / 2 - 50); // if (_editorInpsectorPreview == null || _previousObjectInpectorPreview != // _currentPickObject?.pickedObject) // { // _editorInpsectorPreview = // UnityEditor.Editor.CreateEditor(_currentPickObject?.pickedObject); // } // // var rect = GUILayoutUtility.GetLastRect(); // _editorInpsectorPreview.DrawPreview(new Rect( // new Vector2(position.width / 2 - 50, rect.position.y), // new Vector2(100, 100))); // _previousObjectInpectorPreview = _currentPickObject?.pickedObject; // GUI.color = new Color(1, 1, 1, 0f); // if (GUILayout.Button(tex, GUILayout.Height(80), GUILayout.Width(80))) // { // } // // GUI.color = Color.white; // EditorGUILayout.EndHorizontal(); // // #endregion // // // EditorGUILayout.LabelField( // $"Selected: {pickObjectName}\nPress Icon Again Or Escape Key To Deselect", // new GUIStyle(EditorStyles.label) { richText = true }, // GUILayout.Height(40)); // height -= 128; // EditorGUILayout.HelpBox("Shift + Click To Add", MessageType.Info); // } // else // { // EditorGUILayout.HelpBox("Select An Object First", MessageType.Info); // } // // height -= 100; // if (Uniform.GetFoldoutState("level_editor_drop_area")) // { // if (LevelSystemEditorSetting.Instance.blacklistPaths.Count == 0 && // LevelSystemEditorSetting.Instance.whitelistPaths.Count == 0) // { // height -= 94; // } // else // { // height -= 342; // } // } // else // { // height -= 33; // } // // if (Uniform.GetFoldoutState("level_editor_config")) // { // switch (_optionsSpawn[_selectedSpawn].ToLower()) // { // case "default": // height -= 122; // break; // case "index": // var currentPrefabState = GetCurrentPrefabStage(); // if (currentPrefabState != null) // { // height -= 146; // } // else // { // height -= 162; // } // // break; // case "custom": // height -= 146; // break; // } // } // else // { // height -= 33; // } // // var h = position.height + height; // // _pickObjectScrollPosition = // GUILayout.BeginScrollView(_pickObjectScrollPosition, GUILayout.Height(h)); // var resultSplitGroupObjects = // PickObjects.GroupBy(_ => _.group).Select(_ => _.ToList()).ToList(); // foreach (var splitGroupObject in resultSplitGroupObjects) // { // string nameGroup = splitGroupObject[0].group.ToUpper(); // Uniform.DrawGroupFoldout($"level_editor_pickup_area_child_{nameGroup}", // nameGroup, () => DrawInGroup(splitGroupObject)); // } // // GUILayout.EndScrollView(); // } // // void DrawInGroup(IReadOnlyList pickObjectsInGroup) // { // const int spacing = 25; // var counter = 0; // CalculateIdealCount(position.width - 50, // 60, // 135, // spacing, // 5, // out int count, // out float size); // count = Mathf.Max(1, count); // while (counter >= 0 && counter < pickObjectsInGroup.Count) // { // EditorGUILayout.BeginHorizontal(); // GUILayout.Space(8); // for (var x = 0; x < count; x++) // { // var pickObj = pickObjectsInGroup[counter]; // var go = pickObj.pickedObject; // var tex = LevelEditor.GetPreview(go); // if (pickObj == _currentPickObject) // { // GUI.color = new Color32(79, 213, 255, 255); // } // else // { // GUI.color = Color.white; // } // // if (GUILayout.Button(new GUIContent(""), GUILayout.Width(size), // GUILayout.Height(size))) // { // if (Event.current.button == 1) // { // ShowMenuRightClickItem(pickObj); // } // else // { // _currentPickObject = _currentPickObject == pickObj ? null : pickObj; // } // } // // Rect Grown(Rect r, Vector2 half) // { // return new Rect(r.position - half, r.size + half * 2); // } // // GUI.color = Color.white; // var rect = GUILayoutUtility.GetLastRect(); // if (tex) // GUI.DrawTexture(Grown(rect, Vector2.one * -10), tex, // ScaleMode.ScaleToFit); // if (go) // { // EditorGUI.LabelField(Grown(rect, new Vector2(0, 15)), go.name, // new GUIStyle(EditorStyles.miniLabel) // { alignment = TextAnchor.LowerCenter, }); // } // // counter++; // if (counter >= pickObjectsInGroup.Count) break; // GUILayout.Space(4); // } // // GUILayout.FlexibleSpace(); // EditorGUILayout.EndHorizontal(); // GUILayout.Space(spacing); // } // } // // void ShowMenuRefresh() // { // var menu = new GenericMenu(); // menu.AddItem(new GUIContent("Refresh Pickup Area"), // false, // () => // { // _currentPickObject = null; // RefreshAll(); // }); // menu.ShowAsContext(); // } // // void ShowMenuRightClickItem(PickObject pickObj) // { // var menu = new GenericMenu(); // menu.AddItem(new GUIContent("Ignore"), false, () => IgnorePath(pickObj)); // menu.AddItem(new GUIContent("Ping"), // false, // () => // { // Selection.activeObject = pickObj.pickedObject; // EditorGUIUtility.PingObject(pickObj.pickedObject); // }); // menu.ShowAsContext(); // } // // void IgnorePath(PickObject pickObj) // { // var path = AssetDatabase.GetAssetPath(pickObj.pickedObject); // ValidateBlacklist(path, ref LevelSystemEditorSetting.Instance.whitelistPaths); // AddToBlacklist(path); // ReduceScopeDirectory(ref LevelSystemEditorSetting.Instance.blacklistPaths); // RefreshAll(); // } // } // // private void SaveLevelSystemSetting() // { // EditorUtility.SetDirty(LevelSystemEditorSetting.Instance); // AssetDatabase.SaveAssets(); // } // // private void OnSceneGUI(SceneView sceneView) // { // if (TryClose()) return; // if (CheckEscape()) return; // TryFakeRender(sceneView); // } // // private void TryFakeRender(SceneView sceneView) // { // var e = Event.current; // if (!e.shift) // { // if (_previewPickupObject != null) DestroyImmediate(_previewPickupObject); // return; // } // // if (_currentPickObject == null || !_currentPickObject.pickedObject) return; // Vector3 mousePosition; // Vector3 normal; // if (sceneView.in2DMode) // { // bool state = EditorExtend.Get2DMouseScenePosition(out var mousePosition2d); // mousePosition = mousePosition2d; // if (!state) return; // EditorExtend.FakeRenderSprite(_currentPickObject.pickedObject, mousePosition, // Vector3.one, Quaternion.identity); // SceneView.RepaintAll(); // // if (e.type == EventType.MouseDown && e.button == 0) // { // AddPickObject(_currentPickObject, mousePosition); // EditorExtend.SkipEvent(); // } // } // else // { // var pos = EditorExtend.GetInnerGuiPosition(sceneView); // RaycastHit? raycastHit; // if (pos.Contains(e.mousePosition)) // { // var currentPrefabState = GetCurrentPrefabStage(); // if (currentPrefabState != null) // { // var (mouseCast, hitInfo) = RaycastPoint(GetParent(), EventMousePoint); // mousePosition = mouseCast; // normal = hitInfo.HasValue ? hitInfo.Value.normal : Vector3.up; // raycastHit = hitInfo; // } // else // { // Probe.Pick(ProbeFilter.Default, // sceneView, // e.mousePosition, // out mousePosition, // out normal); // raycastHit = null; // } // // float discSize = HandleUtility.GetHandleSize(mousePosition) * 0.4f; // Handles.color = new Color(1, 0, 0, 0.5f); // Handles.DrawSolidDisc(mousePosition, normal, discSize * 0.5f); // // if (!_previewPickupObject) // { // _previewPickupObject = // (GameObject)PrefabUtility.InstantiatePrefab(_currentPickObject // ?.pickedObject); // StageUtility.PlaceGameObjectInCurrentStage(_previewPickupObject); // _previewPickupObject.hideFlags = HideFlags.HideAndDontSave; // _previewPickupObject.layer = LayerMask.NameToLayer("Ignore Raycast"); // } // // #pragma warning disable CS8321 // void SetPosition2() // { // var rendererAttach = _currentPickObject?.pickedObject // .GetComponentInChildren(); // if (raycastHit == null || rendererAttach == null) return; // var rendererOther = raycastHit.Value.collider.transform // .GetComponentInChildren(); // if (rendererOther == null) return; // _previewPickupObject.transform.position = GetSpawnPosition(rendererAttach, // rendererOther, raycastHit.Value); // } // #pragma warning restore CS8321 // // void SetPosition() // { // _previewPickupObject.transform.position = mousePosition; // // switch (_optionsMode[_selectedMode].ToLower()) // { // case "renderer": // if (_previewPickupObject.CalculateBounds(out var bounds, // Space.World, // true, // false, // false, // false)) // { // float difference = 0; // // if (normal == Vector3.up || normal == Vector3.down) // { // difference = mousePosition.y - bounds.min.y; // } // else if (normal == Vector3.right || normal == Vector3.left) // { // difference = mousePosition.x - bounds.min.x; // } // else if (normal == Vector3.forward || normal == Vector3.back) // { // difference = mousePosition.z - bounds.min.z; // } // // _previewPickupObject.transform.position += difference * normal; // } // // break; // case "ignore": // break; // } // } // // SetPosition(); // // if (e.type == EventType.MouseDown && e.button == 0 && _previewPickupObject) // { // AddPickObject(_currentPickObject, _previewPickupObject.transform.position); // EditorExtend.SkipEvent(); // } // } // } // } // // /// // /// only use when determined root // /// // /// // /// // /// // /// // private (bool, RaycastHit?) RayCast(Component root, Ray ray, out Vector3 point) // { // point = Vector3.zero; // if (root.gameObject.scene.GetPhysicsScene() // .Raycast(ray.origin, ray.direction, out var hit)) // { // point = hit.point; // return (true, hit); // } // // return (false, null); // } // // /// // /// only use when determined root // /// // /// // /// // /// // /// // private (Vector3, RaycastHit?) RaycastPoint(Component root, Vector2 screenPoint, // float distance = 20) // { // var ray = SceneView.currentDrawingSceneView.camera.ScreenPointToRay(screenPoint); // var result = RayCast(root, ray, out var point); // if (!result.Item1) // { // point = ray.origin + ray.direction.normalized * distance; // } // // return (point, result.Item2); // } // // /// // /// for mesh with irregular shape the returned result is incorrect // /// missing some direction // /// // /// // /// // /// // /// // private Vector3 GetSpawnPosition(Renderer rendererAttach, Renderer rendererOther, // RaycastHit hitInfo) // { // var boundsAttach = rendererAttach.bounds; // var boundsOther = rendererOther.bounds; // // var otherPos = hitInfo.collider.gameObject.transform.position; // var pointPos = hitInfo.point; // // int isSpawnRighSide; // if (Mathf.Abs(otherPos.x - pointPos.x) >= boundsOther.size.x / 2) // { // isSpawnRighSide = otherPos.x > pointPos.x ? -1 : 1; // } // else // { // isSpawnRighSide = 0; // } // // int isSpawnUpSide; // if (Mathf.Abs(otherPos.y - pointPos.y) >= boundsOther.size.y / 2) // { // isSpawnUpSide = otherPos.y > pointPos.y ? -1 : 1; // } // else // { // isSpawnUpSide = 0; // } // // int isSpawnForwardSide; // if (Mathf.Abs(otherPos.z - pointPos.z) >= boundsOther.size.z / 2) // { // isSpawnForwardSide = otherPos.z > pointPos.z ? -1 : 1; // } // else // { // isSpawnForwardSide = 0; // } // // return new Vector3(hitInfo.point.x + (boundsAttach.size.x / 2 * isSpawnRighSide), // hitInfo.point.y + (boundsAttach.size.y / 2 * isSpawnUpSide), // hitInfo.point.z + (boundsAttach.size.z / 2 * isSpawnForwardSide)); // } // // /// // /// Spawn pickup object // /// // /// // /// // private void AddPickObject(PickObject pickObject, Vector3 worldPos) // { // if (pickObject?.pickedObject) // { // var inst = // (GameObject)PrefabUtility.InstantiatePrefab(pickObject.pickedObject, // GetParent()); // inst.transform.position = worldPos; // Undo.RegisterCreatedObjectUndo(inst.gameObject, "Create pick obj"); // Selection.activeObject = inst; // } // } // // private Transform GetParent() // { // Transform parent = null; // var currentPrefabState = GetCurrentPrefabStage(); // // if (currentPrefabState != null) // { // var prefabRoot = currentPrefabState.prefabContentsRoot.transform; // switch (_optionsSpawn[_selectedSpawn].ToLower()) // { // case "default": // parent = prefabRoot; // break; // case "index": // if (_rootIndexSpawn < 0) parent = prefabRoot; // else if (prefabRoot.childCount - 1 > _rootIndexSpawn) // parent = prefabRoot.GetChild(_rootIndexSpawn); // else parent = prefabRoot; // break; // case "custom": // parent = _rootSpawn ? _rootSpawn.transform : prefabRoot; // break; // } // } // else // { // switch (_optionsSpawn[_selectedSpawn].ToLower()) // { // case "default": // case "index": // parent = null; // break; // case "custom": // parent = _rootSpawn ? _rootSpawn.transform : null; // break; // } // } // // return parent; // } // // private PrefabStage GetCurrentPrefabStage() // { // return PrefabStageUtility.GetCurrentPrefabStage(); // } // // /// // /// Calculate count item pickup can display // /// // /// // /// // /// // /// // /// // /// // /// // /// // // ReSharper disable once UnusedMethodReturnValue.Local // private static bool CalculateIdealCount(float availableSpace, float minSize, float maxSize, // float spacing, int defaultCount, out int count, out float size) // { // float halfSpacing = spacing / 2f; // int minCount = Mathf.FloorToInt(availableSpace / (maxSize + halfSpacing)); // int maxCount = Mathf.FloorToInt(availableSpace / (minSize + halfSpacing)); // bool goodness = defaultCount >= minCount && defaultCount <= maxCount; // count = Mathf.Clamp(defaultCount, minCount, maxCount); // size = (availableSpace - halfSpacing * (count - 1) - (count - 1) * (count / 10f)) / // count; // return goodness; // } // // private void ClearEditor() // { // Repaint(); // } } } ================================================ FILE: VirtueSky/LevelEditor/LevelEditor.cs.meta ================================================ fileFormatVersion: 2 guid: 732ddfe59241fd34ab461578cb96db31 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/LevelEditor/LevelSystemEditorSetting.cs ================================================ using System; using System.Collections.Generic; using UnityEditor; using UnityEngine; using VirtueSky.Utils; namespace VirtueSky.LevelEditor { [Serializable] public class LevelSystemEditorSetting : ScriptableSettings { public List whitelistPaths = new List(); public List blacklistPaths = new List(); public readonly string[] optionsSpawn = { "Default", "Index", "Custom" }; public readonly string[] optionsMode = { "Renderer", "Ignore" }; public Vector2 SettingTabScrollPosition { get; set; } = Vector2.zero; public Vector2 PickObjectScrollPosition { get; set; } = Vector2.zero; public Vector2 WhitelistScrollPosition { get; set; } public Vector2 BlacklistScrollPosition { get; set; } public PickObject CurrentPickObject { get; set; } public List PickObjects { get; set; } = new List(); public SerializedObject _pathFolderSerializedObject; public SerializedProperty _pathFolderProperty; public int SelectedSpawn { get; set; } public int SelectedMode { get; set; } public GameObject RootSpawn { get; set; } public int RootIndexSpawn { get; set; } public GameObject PreviewPickupObject { get; set; } public UnityEngine.Object PreviousObjectInspectorPreview { get; set; } public UnityEditor.Editor EditorInspectorPreview { get; set; } } public enum LevelEditorTabType { Setting, Pickup } public static class UtilitiesLevelSystemDrawer { // [MenuItem("Sunflower/LevelEditor &3")] // public static void OpenLevelEditor() // { // OnInspectorGUI(); // } // public static void OnInspectorGUI() // { // var scriptableSetting = Resources.Load(nameof(LevelSystemEditorSetting)); // if (scriptableSetting == null) // { // GUI.enabled = !EditorApplication.isCompiling; // GUI.backgroundColor = Uniform.Pink; // var setting = ScriptableObject.CreateInstance(); // const string path = "Assets/_Sunflower/Editor/Resources"; // if (!Directory.Exists(path)) Directory.CreateDirectory(path); // AssetDatabase.CreateAsset(setting, $"{path}/{nameof(LevelSystemEditorSetting)}.asset"); // RegistryManager.Add("com.unity.addressables", "1.21.19"); // RegistryManager.Resolve(); // AssetDatabase.SaveAssets(); // AssetDatabase.Refresh(); // Debug.Log( // $"{nameof(LevelSystemEditorSetting)} was created ad {path}/{nameof(LevelSystemEditorSetting)}.asset"); // GUI.backgroundColor = Color.white; // GUI.enabled = true; // // OpenWindowLevelEditor(); // } // else // { // OpenWindowLevelEditor(); // } // } // // static void OpenWindowLevelEditor() // { // var window = EditorWindow.GetWindow("Level Editor", true); // if (window) // { // window.minSize = new Vector2(275, 0); // window.Show(true); // } // } } } ================================================ FILE: VirtueSky/LevelEditor/LevelSystemEditorSetting.cs.meta ================================================ fileFormatVersion: 2 guid: 2cf7fd915596441e97e1ada0052356b4 timeCreated: 1697171875 ================================================ FILE: VirtueSky/LevelEditor/PickObject.cs ================================================ using UnityEngine; namespace VirtueSky.LevelEditor { public class PickObject { public string group; public GameObject pickedObject; } } ================================================ FILE: VirtueSky/LevelEditor/PickObject.cs.meta ================================================ fileFormatVersion: 2 guid: abcdf4f25e5d48ad87be9afa4e129744 timeCreated: 1707213556 ================================================ FILE: VirtueSky/LevelEditor/PreviewGenerator.cs ================================================ using System; using System.Linq; using UnityEngine; using VirtueSky.UtilsEditor; using Object = UnityEngine.Object; namespace VirtueSky.LevelEditor { public class PreviewGenerator { public static readonly PreviewGenerator Default = new PreviewGenerator(); private const int MAX_TEXTURE_SIZE = 2048; private static int latePreviewQueued; // ReSharper disable once MemberCanBePrivate.Global public Vector3 previewPosition = new Vector3(9999, 9999, -9999); // ReSharper disable once MemberCanBePrivate.Global public Vector3 latePreviewOffset = new Vector3(100, 100, 0); public bool transparentBackground = true; // ReSharper disable once MemberCanBePrivate.Global public Color solidBackgroundColor = new Color(0.3f, 0.3f, 0.3f); // ReSharper disable once MemberCanBePrivate.Global public FilterMode imageFilterMode = FilterMode.Point; public ImageSizeType sizingType = ImageSizeType.PixelsPerUnit; // ReSharper disable once MemberCanBePrivate.Global public int pixelPerUnit = 32; public int width = 256; public int height = 256; // ReSharper disable once MemberCanBePrivate.Global public float timingCounter = 1; // ReSharper disable once MemberCanBePrivate.Global public Action onCapturedCallback; // ReSharper disable once MemberCanBePrivate.Global public Action onPreCaptureCallback; public enum ImageSizeType { PixelsPerUnit, Fit, Fill, Stretch, } public PreviewGenerator Copy() { return new PreviewGenerator() { previewPosition = previewPosition, latePreviewOffset = latePreviewOffset, transparentBackground = transparentBackground, solidBackgroundColor = solidBackgroundColor, imageFilterMode = imageFilterMode, sizingType = sizingType, pixelPerUnit = pixelPerUnit, width = width, height = height, timingCounter = timingCounter, onCapturedCallback = onCapturedCallback, onPreCaptureCallback = onPreCaptureCallback, }; } public PreviewGenerator OnCaptured(Action callback) { onCapturedCallback = callback; return this; } public PreviewGenerator OnPreCaptured(Action callback) { onPreCaptureCallback = callback; return this; } public Texture2D CreatePreview(GameObject obj, bool clone = true) { if (!CanCreatePreview(obj)) { onCapturedCallback?.Invoke(null); return EditorResources.ScriptableFactory; } var cachedPosition = obj.transform.position; var prevObj = clone ? Object.Instantiate(obj, null) : obj; prevObj.transform.position = previewPosition + latePreviewQueued * latePreviewOffset; var bounds = GetBounds(prevObj, false); var size = GetImageSize(bounds); var cam = CreatePreviewCamera(bounds); var light = CreatePreviewLight(bounds); latePreviewQueued++; var dummy = new GameObject("Preview Dummy"); void Callback() { latePreviewQueued--; if (clone) { Object.DestroyImmediate(prevObj); } else { prevObj.transform.position = cachedPosition; } Object.DestroyImmediate(cam.gameObject); Object.DestroyImmediate(light.gameObject); Object.DestroyImmediate(dummy.gameObject); } return WrappedCapture(prevObj, cam, size.x, size.y, Callback); } private void NotifyPreviewTaking(GameObject go, Action action) { var allComps = go.GetComponentsInChildren(); foreach (var comp in allComps) { // ReSharper disable once SuspiciousTypeConversion.Global if (comp is IPreviewComponent component) action?.Invoke(component); } } private bool CanCreatePreview(GameObject obj) { return obj != null && obj.GetComponentsInChildren().Any(r => r != null && r.enabled); } private Camera CreatePreviewCamera(Bounds bounds) { var camObj = new GameObject("Preview generator camera"); var cam = camObj.AddComponent(); cam.transform.position = bounds.center + Vector3.back * (bounds.extents.z + 2); cam.nearClipPlane = 0.01f; cam.farClipPlane = bounds.size.z + 4; cam.orthographic = true; cam.orthographicSize = bounds.extents.y; cam.aspect = bounds.extents.x / bounds.extents.y; cam.clearFlags = CameraClearFlags.Color; cam.backgroundColor = solidBackgroundColor; if (transparentBackground) cam.backgroundColor *= 0; cam.enabled = false; return cam; } private Light CreatePreviewLight(Bounds bounds) { var lightObj = new GameObject("Preview generator light"); var light = lightObj.AddComponent(); light.type = LightType.Directional; light.transform.position = bounds.center + Vector3.back * (bounds.extents.z + 2); light.color = Color.white; light.intensity = 1; return light; } private Vector2Int GetImageSize(Bounds bounds) { var w = 1; var h = 1; if (sizingType == ImageSizeType.PixelsPerUnit) { w = Mathf.CeilToInt(bounds.size.x * pixelPerUnit); h = Mathf.CeilToInt(bounds.size.y * pixelPerUnit); } else if (sizingType == ImageSizeType.Stretch) { w = width; h = height; } else if (sizingType == ImageSizeType.Fit || sizingType == ImageSizeType.Fill) { float widthFactor = width / bounds.size.x; float heightFactor = height / bounds.size.y; float factor = sizingType == ImageSizeType.Fit ? Mathf.Min(widthFactor, heightFactor) : Mathf.Max(widthFactor, heightFactor); w = Mathf.CeilToInt(bounds.size.x * factor); h = Mathf.CeilToInt(bounds.size.y * factor); } if (w > MAX_TEXTURE_SIZE || h > MAX_TEXTURE_SIZE) { float downscaleWidthFactor = (float)MAX_TEXTURE_SIZE / w; float downscaleHeightFactor = (float)MAX_TEXTURE_SIZE / h; float downscaleFactor = Mathf.Min(downscaleWidthFactor, downscaleHeightFactor); w = Mathf.CeilToInt(w * downscaleFactor); h = Mathf.CeilToInt(h * downscaleFactor); } return new Vector2Int(w, h); } private Texture2D WrappedCapture(GameObject obj, Camera cam, int w, int h, Action callback) { onPreCaptureCallback?.Invoke(obj); NotifyPreviewTaking(obj, i => i.OnPreviewCapturing(this)); var tex = DoCapture(cam, w, h); NotifyPreviewTaking(obj, i => i.OnPreviewCaptured(this)); callback?.Invoke(); onCapturedCallback?.Invoke(tex); return tex; } private Texture2D DoCapture(Camera cam, int w, int h) { var temp = RenderTexture.active; RenderTexture renderTex = null; try { renderTex = RenderTexture.GetTemporary(w, h, 16); } catch (Exception) { // } RenderTexture.active = renderTex; cam.enabled = true; cam.targetTexture = renderTex; cam.Render(); cam.targetTexture = null; cam.enabled = false; if (w <= 0) w = 512; if (h <= 0) h = 512; var tex = new Texture2D(w, h, transparentBackground ? TextureFormat.RGBA32 : TextureFormat.RGB24, false) { filterMode = imageFilterMode }; tex.ReadPixels(new Rect(0, 0, w, h), 0, 0, false); tex.Apply(false, false); RenderTexture.active = temp; RenderTexture.ReleaseTemporary(renderTex); return tex; } /// /// Get bound of gameobject via collider or renderer /// /// /// /// /// /// private Bounds GetBounds(GameObject go, bool includeInactive = true, System.Func getBounds = null) where T : Component { if (getBounds == null) getBounds = (t) => (t as Collider)?.bounds ?? (t as Collider2D)?.bounds ?? (t as Renderer)?.bounds ?? default; var comps = go.GetComponentsInChildren(includeInactive).Where(_ => !(_.gameObject.GetComponent())).ToArray(); Bounds bound = default; bool found = false; foreach (var comp in comps) { if (comp) { if (!includeInactive) { if (!(comp as Collider)?.enabled ?? false) continue; if (!(comp as Collider2D)?.enabled ?? false) continue; if (!(comp as Renderer)?.enabled ?? false) continue; if (!(comp as MonoBehaviour)?.enabled ?? false) continue; } if (!found || bound.size == Vector3.zero) { bound = getBounds(comp); found = true; } else bound.Encapsulate(getBounds(comp)); } } return bound; } } internal interface IPreviewComponent { void OnPreviewCapturing(PreviewGenerator preview); void OnPreviewCaptured(PreviewGenerator preview); } } ================================================ FILE: VirtueSky/LevelEditor/PreviewGenerator.cs.meta ================================================ fileFormatVersion: 2 guid: 916e32408cb546d5b9e85d4ee87e0281 timeCreated: 1697172001 ================================================ FILE: VirtueSky/LevelEditor/Probe.cs ================================================ namespace VirtueSky.LevelEditor { using System; using System.Collections.Generic; using System.Linq; using UnityEditor; using UnityEngine; public delegate void ProbeHitSelectHandler(bool add); public struct ProbeHit { public GameObject gameObject; public Vector3? point; public Vector3? normal; public float? distance; public string label; public ProbeHitSelectHandler selectHandler; public Action focusHandler; public Action lostFocusHandler; public Transform Transform { get => gameObject.transform; set => gameObject = value.gameObject; } public RectTransform RectTransform { get => gameObject.GetComponent(); set => gameObject = value.gameObject; } public GameObject groupGameObject; public double groupOrder; public ProbeHit(GameObject gameObject) { this.gameObject = gameObject; this.groupGameObject = gameObject; groupOrder = 0; point = default; normal = default; distance = default; label = default; selectHandler = default; focusHandler = default; lostFocusHandler = default; } public void Select(bool add) { if (selectHandler != null) { selectHandler(add); } else if (gameObject != null) { if (add) { Selection.objects = Selection.objects.Append(gameObject).ToArray(); } else { Selection.activeGameObject = gameObject; } } } public void OnFocusEnter() { if (focusHandler != null) { focusHandler.Invoke(); } else { Probe.Highlight(gameObject); } } public void OnFocusLeave() { if (lostFocusHandler != null) { lostFocusHandler.Invoke(); } else { Probe.ClearHighlight(); } } } public static class Probe { #region Object Picking private const int DEFAULT_LIMIT = 100; private static bool CanPickHandles => E != null && (E.type == EventType.MouseMove || E.type == EventType.MouseDown || E.type == EventType.MouseUp || E.type == EventType.MouseDrag || E.type == EventType.MouseEnterWindow || E.type == EventType.MouseLeaveWindow); public static ProbeHit? Pick(ProbeFilter filter, SceneView sceneView, Vector2 guiPosition, out Vector3 point) { var results = new List(); try { PickAllNonAlloc(results, filter, sceneView, guiPosition); foreach (var result in results) { if (result.point.HasValue) { point = result.point.Value; return result; } } point = DefaultPoint(sceneView, guiPosition); return null; } finally { results = null; } } public static ProbeHit? Pick(ProbeFilter filter, SceneView sceneView, Vector2 guiPosition, out Vector3 point, out Vector3 normal) { var results = new List(); try { PickAllNonAlloc(results, filter, sceneView, guiPosition); foreach (var result in results) { if (result.point.HasValue && result.normal.HasValue) { point = result.point.Value; normal = result.normal.Value; return result; } } point = DefaultPoint(sceneView, guiPosition); normal = Vector3.up; return null; } finally { results = null; } } public static ProbeHit[] PickAll(ProbeFilter filter, SceneView sceneView, Vector2 guiPosition, int limit = DEFAULT_LIMIT) { var results = new List(); PickAllNonAlloc(results, filter, sceneView, guiPosition, limit); return results.ToArray(); } private static void PickAllNonAlloc(List hits, ProbeFilter filter, SceneView sceneView, Vector2 guiPosition, int limit = DEFAULT_LIMIT) { var screenPosition = HandleUtility.GUIPointToScreenPixelCoordinate(guiPosition); var ray3D = HandleUtility.GUIPointToWorldRay(guiPosition); var worldPosition = sceneView.camera.ScreenToWorldPoint(screenPosition); var layerMask = Physics.DefaultRaycastLayers; var raycastHits = new RaycastHit[limit]; var overlapHits = new Collider2D[limit]; var handleHits = new HashSet(); var ancestorHits = new HashSet(); var gameObjectHits = new Dictionary(); try { // Raycast (3D) if (filter.Raycast) { var raycastHitCount = Physics.RaycastNonAlloc(ray3D, raycastHits, Mathf.Infinity, layerMask); for (var i = 0; i < raycastHitCount; i++) { var raycastHit = raycastHits[i]; #if UNITY_2019_2_OR_NEWER if (SceneVisibilityManager.instance.IsHidden(raycastHit.transform.gameObject)) { continue; } #endif var gameObject = raycastHit.transform.gameObject; if (!gameObjectHits.TryGetValue(gameObject, out var hit)) { hit = new ProbeHit(gameObject); } hit.point = raycastHit.point; hit.normal = raycastHit.normal; hit.distance = raycastHit.distance; gameObjectHits[gameObject] = hit; } } // Overlap (2D) if (filter.Overlap) { var overlapHitCount = Physics2D.OverlapPointNonAlloc(worldPosition, overlapHits, layerMask); for (var i = 0; i < overlapHitCount; i++) { var overlapHit = overlapHits[i]; #if UNITY_2019_2_OR_NEWER if (SceneVisibilityManager.instance.IsHidden(overlapHit.transform.gameObject)) { continue; } #endif var gameObject = overlapHit.transform.gameObject; if (!gameObjectHits.TryGetValue(gameObject, out var hit)) { hit = new ProbeHit(gameObject); } hit.distance = hit.distance ?? Vector3.Distance(overlapHit.transform.position, worldPosition); gameObjectHits[gameObject] = hit; } } // Handles (Editor Default) if (filter.Handles && CanPickHandles) { PickAllHandlesNonAlloc(handleHits, guiPosition, limit); foreach (var handleHit in handleHits) { var gameObject = handleHit; if (!gameObjectHits.TryGetValue(gameObject, out var hit)) { hit = new ProbeHit(gameObject); } hit.distance = hit.distance ?? Vector3.Distance(handleHit.transform.position, worldPosition); gameObjectHits[gameObject] = hit; } } // Ancestors foreach (var gameObjectHit in gameObjectHits) { var gameObject = gameObjectHit.Key; var hit = gameObjectHit.Value; var parent = gameObject.transform.parent; int depth = 0; while (parent != null) { var parentGameObject = parent.gameObject; var parentHit = new ProbeHit(parentGameObject); parentHit.groupGameObject = gameObject; parentHit.distance = hit.distance ?? Vector3.Distance(parentHit.Transform.position, worldPosition); parentHit.groupOrder = 1000 + depth; ancestorHits.Add(parentHit); parent = parent.parent; depth++; } } // Prepare final hits hits.Clear(); // Add hits foreach (var gameObjectHit in gameObjectHits.Values) { hits.Add(gameObjectHit); } foreach (var ancestorHit in ancestorHits) { hits.Add(ancestorHit); } // Sort by distance hits.Sort(CompareHits); } finally { raycastHits = null; overlapHits = null; handleHits.Clear(); ancestorHits.Clear(); gameObjectHits.Clear(); handleHits = null; ancestorHits = null; gameObjectHits = null; } } private static void PickAllHandlesNonAlloc(HashSet results, Vector2 position, int limit = DEFAULT_LIMIT) { if (!CanPickHandles) { // HandleUtility.PickGameObject is not supported in those contexts Debug.LogWarning($"Cannot pick game objects in the current event: {E?.ToString() ?? "null"}"); return; } GameObject result; var count = 0; do { var ignored = results.ToArray(); result = HandleUtility.PickGameObject(position, false, ignored); // Ignored doesn't seem very reliable. Sometimes, an item included // in ignored will still be returned. That's a sign we should stop. if (results.Contains(result)) { result = null; } if (result != null) { results.Add(result); } } while (result != null && count++ < limit); } private static readonly Comparison CompareHits = CompareProbeHit; private static int CompareProbeHit(ProbeHit a, ProbeHit b) { var distanceA = a.distance ?? Mathf.Infinity; var distanceB = b.distance ?? Mathf.Infinity; return distanceA.CompareTo(distanceB); } private static Vector3 DefaultPoint(SceneView sceneView, Vector2 guiPosition) { var screenPosition = (Vector3)HandleUtility.GUIPointToScreenPixelCoordinate(guiPosition); screenPosition.z = sceneView.cameraDistance; return sceneView.camera.ScreenToWorldPoint(screenPosition); } #endregion #region Scene View Integration private static Event E => Event.current; private static Vector2? pressPosition; private static GameObject highlight; internal static void Highlight(GameObject selection) { highlight = selection; SceneView.RepaintAll(); } internal static void ClearHighlight() { highlight = null; SceneView.RepaintAll(); } #endregion } public struct ProbeFilter { public bool Raycast { get; set; } public bool Overlap { get; set; } public bool Handles { get; set; } public static ProbeFilter Default { get; } = new ProbeFilter { Raycast = true, Overlap = true, Handles = true }; } } ================================================ FILE: VirtueSky/LevelEditor/Probe.cs.meta ================================================ fileFormatVersion: 2 guid: 1618f116123449a397a2fc8f647bb28e timeCreated: 1697172426 ================================================ FILE: VirtueSky/LevelEditor/virtuesky.sunflower.leveleditor.asmdef ================================================ { "name": "Virtuesky.Sunflower.LevelEditor", "rootNamespace": "", "references": [ "GUID:c282fd4f3fc2c7540914e85842a013c7", "GUID:c904f6d969e991d459a0843b71c22ec5", "GUID:fca7ec166e04dc948b624a983315e2c9", "GUID:0b6289df6f84a6f4b982ff72d23e0273", "GUID:324caed91501a9c47a04ebfd87b68794" ], "includePlatforms": [ "Editor" ], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], "versionDefines": [], "noEngineReferences": false } ================================================ FILE: VirtueSky/LevelEditor/virtuesky.sunflower.leveleditor.asmdef.meta ================================================ fileFormatVersion: 2 guid: b1979aef4cc42ae46af23ce2c4c109cc AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/LevelEditor.meta ================================================ fileFormatVersion: 2 guid: 18624879c63c4603b36a29a52fd1f076 timeCreated: 1697171489 ================================================ FILE: VirtueSky/Linq/Aggregate.cs ================================================ using System; using System.Collections.Generic; namespace VirtueSky.Linq { /// /// Provides faster array and list specific extension methods with /// the same semantics as the Linq extensions methods. /// public static partial class L { // ------------------------------ Arrays -------------------------- /// /// Applies an accumulator function over an array. /// /// An array to aggregate over. /// An accumulator function to be invoked on each element /// The final accumulator value public static TSource Reduce(this TSource[] source, Func func) { if (source == null) throw new ArgumentNullException(nameof(source)); if (func == null) throw new ArgumentNullException(nameof(func)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); TSource result = source[0]; for (int i = 1; i < source.Length; i++) { result = func(result, source[i]); } return result; } /// /// Applies an accumulator function over an array. The specified seed /// value is used as the initial accumulator value. /// /// An array to aggregate over. /// The initial accumulator value. /// An accumulator function to be invoked on each element /// The final accumulator value public static TAccumulate Reduce(this TSource[] source, TAccumulate seed, Func func) { if (source == null) throw new ArgumentNullException(nameof(source)); if (func == null) throw new ArgumentNullException(nameof(func)); TAccumulate result = seed; foreach (var v in source) { result = func(result, v); } return result; } /// /// Applies an accumulator function over an array. The specified seed /// value is used as the initial accumulator value, and the specified /// function is used to select the result value. /// /// An array to aggregate over. /// The initial accumulator value. /// An accumulator function to be invoked on each element /// A function to transform the final accumulator value into the result value. /// The transformed final accumulator value public static TResult Reduce( this TSource[] source, TAccumulate seed, Func func, Func resultSelector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (func == null) throw new ArgumentNullException(nameof(func)); if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector)); TAccumulate result = seed; foreach (var v in source) { result = func(result, v); } return resultSelector(result); } // ------------------------------ this Spans -------------------------- #if UNITY_2021_3_OR_NEWER /// /// Applies an accumulator function over an array. /// /// An array to aggregate over. /// An accumulator function to be invoked on each element /// The final accumulator value public static TSource Reduce(this Span source, Func func) { if (source == null) throw new ArgumentNullException(nameof(source)); if (func == null) throw new ArgumentNullException(nameof(func)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); TSource result = source[0]; for (int i = 1; i < source.Length; i++) { result = func(result, source[i]); } return result; } /// /// Applies an accumulator function over an array. The specified seed /// value is used as the initial accumulator value. /// /// An array to aggregate over. /// The initial accumulator value. /// An accumulator function to be invoked on each element /// The final accumulator value public static TAccumulate Reduce(this Span source, TAccumulate seed, Func func) { if (source == null) throw new ArgumentNullException(nameof(source)); if (func == null) throw new ArgumentNullException(nameof(func)); TAccumulate result = seed; foreach (var v in source) { result = func(result, v); } return result; } /// /// Applies an accumulator function over an array. The specified seed /// value is used as the initial accumulator value, and the specified /// function is used to select the result value. /// /// An array to aggregate over. /// The initial accumulator value. /// An accumulator function to be invoked on each element /// A function to transform the final accumulator value into the result value. /// The transformed final accumulator value public static TResult Reduce( this Span source, TAccumulate seed, Func func, Func resultSelector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (func == null) throw new ArgumentNullException(nameof(func)); if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector)); TAccumulate result = seed; foreach (var v in source) { result = func(result, v); } return resultSelector(result); } #endif // ------------------------------ Lists -------------------------- /// /// Applies an accumulator function over a List. /// /// /// A List to aggregate over. /// An accumulator function to be invoked on each element /// The final accumulator value public static TSource Reduce(this List source, Func func) { if (source == null) throw new ArgumentNullException(nameof(source)); if (func == null) throw new ArgumentNullException(nameof(func)); if (source.Count == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); TSource result = source[0]; for (int i = 1; i < source.Count; i++) { result = func(result, source[i]); } return result; } /// /// Applies an accumulator function over a List. The specified seed /// value is used as the initial accumulator value. /// /// A List to aggregate over. /// The initial accumulator value. /// An accumulator function to be invoked on each element /// The final accumulator value public static TAccumulate Reduce(this List source, TAccumulate seed, Func func) { if (source == null) throw new ArgumentNullException(nameof(source)); if (func == null) throw new ArgumentNullException(nameof(func)); TAccumulate result = seed; for (int i = 0; i < source.Count; i++) { result = func(result, source[i]); } return result; } /// /// Applies an accumulator function over a List. The specified seed /// value is used as the initial accumulator value, and the specified /// function is used to select the result value. /// /// A List to aggregate over. /// The initial accumulator value. /// An accumulator function to be invoked on each element /// A function to transform the final accumulator value into the result value. /// The transformed final accumulator value public static TResult Reduce( this List source, TAccumulate seed, Func func, Func resultSelector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (func == null) throw new ArgumentNullException(nameof(func)); if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector)); TAccumulate result = seed; for (int i = 0; i < source.Count; i++) { result = func(result, source[i]); } return resultSelector(result); } } } ================================================ FILE: VirtueSky/Linq/Aggregate.cs.meta ================================================ fileFormatVersion: 2 guid: 7318fcfc949ae1e45a0fb682dc976e17 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Linq/AnyAll.cs ================================================ using System; using System.Collections.Generic; namespace VirtueSky.Linq { public static partial class L { // -------------------------- ARRAYS -------------------------------------------- /// /// Determines whether an array contains any elements /// /// The array to check for emptiness /// true if the source array contains any elements, otherwise, false/ public static bool Any(this T[] source) { if (source == null) throw new ArgumentNullException(nameof(source)); return source.Length > 0; } /// /// Determines whether any element of an array satisfies a condition. /// /// An array whose elements to apply the predicate to. /// A function to test each element for a condition. /// true if any elements in the source array pass the test in the specified predicate; otherwise, false. public static bool Any(this TSource[] source, Predicate predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); return Array.Exists(source, predicate); } /// /// Determines whether all elements of an array satisfy a condition. /// /// An array that contains the elements to apply the predicate to. /// A function to test each element for a condition. /// true if every element of the source array passes the test in the specified /// predicate, or if the array is empty; otherwise, false public static bool AllF(this TSource[] source, Predicate predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); return Array.TrueForAll(source, predicate); } // -------------------------- this SpanS -------------------------------------------- #if UNITY_2021_3_OR_NEWER /// /// Determines whether an array contains any elements /// /// The array to check for emptiness /// true if the source array contains any elements, otherwise, false/ public static bool Any(this Span source) { if (source == null) throw new ArgumentNullException(nameof(source)); return source.Length > 0; } /// /// Determines whether any element of an array satisfies a condition. /// /// An array whose elements to apply the predicate to. /// A function to test each element for a condition. /// true if any elements in the source array pass the test in the specified predicate; otherwise, false. public static bool Any(this Span source, Predicate predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); for (int i = 0; i < source.Length; i++) { if (predicate(source[i])) return true; } return false; } /// /// Determines whether all elements of an array satisfy a condition. /// /// An array that contains the elements to apply the predicate to. /// A function to test each element for a condition. /// true if every element of the source array passes the test in the specified /// predicate, or if the array is empty; otherwise, false public static bool AllF(this Span source, Predicate predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); for (int i = 0; i < source.Length; i++) { if (!predicate(source[i])) return false; } return true; } #endif // -------------------------- Lists -------------------------------------------- /// /// Determines whether a list contains any elements /// /// The list to check for emptiness /// true if the source list contains any elements, otherwise, false/ public static bool Any(this List source) { if (source == null) throw new ArgumentNullException(nameof(source)); return source.Count > 0; } /// /// Determines whether any element of an array satisfies a condition. /// /// An array whose elements to apply the predicate to. /// A function to test each element for a condition. /// true if any elements in the source array pass the test in the specified predicate; otherwise, false. public static bool Any(this List source, Predicate predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); return source.Exists(predicate); } /// /// Determines whether all elements of a list satisfy a condition. /// /// A list that contains the elements to apply the predicate to. /// A function to test each element for a condition. /// true if every element of the source array passes the test in the specified /// predicate, or if the list is empty; otherwise, false public static bool AllF(this List source, Predicate predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); return source.TrueForAll(predicate); } } } ================================================ FILE: VirtueSky/Linq/AnyAll.cs.meta ================================================ fileFormatVersion: 2 guid: 79a5d5f5ebe679e439be08f9273ee22a MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Linq/Average.cs ================================================ using System; using System.Collections.Generic; namespace VirtueSky.Linq { public static partial class L { // -------------------------- ARRAYS -------------------------------------------- /// /// Computes the average of an array /// /// The array to calculate the average of. /// The average of the array. public static double Average(this int[] source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); long sum = 0; checked { for (int i = 0; i < source.Length; i++) { sum += source[i]; } } return (double)sum / source.Length; } /// /// Computes the average of values obtained by invoking a transform function on /// each element of the input array. /// /// The array to calculate the transformed average of. /// A transform function to apply to each element. /// The average of the array. public static double Average(this T[] source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); if (selector == null) throw new ArgumentNullException(nameof(selector)); long sum = 0; checked { for (int i = 0; i < source.Length; i++) { sum += selector(source[i]); } } return (double)sum / source.Length; } /// /// Computes the average of an array /// /// The array to calculate the average of. /// The average of the array. public static double Average(this long[] source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); long sum = 0; checked { for (int i = 0; i < source.Length; i++) { sum += source[i]; } } return (double)sum / source.Length; } /// /// Computes the average of values obtained by invoking a transform function on /// each element of the input array. /// /// The array to calculate the transformed average of. /// A transform function to apply to each element. /// The average of the array. public static double Average(this T[] source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); if (selector == null) throw new ArgumentNullException(nameof(selector)); long sum = 0; checked { for (int i = 0; i < source.Length; i++) { sum += selector(source[i]); } } return (double)sum / source.Length; } /// /// Computes the average of an array /// /// The array to calculate the average of. /// The average of the array. public static float Average(this float[] source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); double sum = 0; for (int i = 0; i < source.Length; i++) { sum += source[i]; } return (float)(sum / source.Length); } /// /// Computes the average of values obtained by invoking a transform function on /// each element of the input array. /// /// The array to calculate the transformed average of. /// A transform function to apply to each element. /// The average of the array. public static float Average(this T[] source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); if (selector == null) throw new ArgumentNullException(nameof(selector)); double sum = 0; for (int i = 0; i < source.Length; i++) { sum += selector(source[i]); } return (float)(sum / source.Length); } /// /// Computes the average of an array /// /// The array to calculate the average of. /// The average of the array. public static double Average(this double[] source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); double sum = 0; for (int i = 0; i < source.Length; i++) { sum += source[i]; } return sum / source.Length; } /// /// Computes the average of values obtained by invoking a transform function on /// each element of the input array. /// /// The array to calculate the transformed average of. /// A transform function to apply to each element. /// The average of the array. public static double Average(this T[] source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); if (selector == null) throw new ArgumentNullException(nameof(selector)); double sum = 0; for (int i = 0; i < source.Length; i++) { sum += selector(source[i]); } return sum / source.Length; } /// /// Computes the average of an array /// /// The array to calculate the average of. /// The average of the array. public static decimal Average(this decimal[] source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); decimal sum = 0; for (int i = 0; i < source.Length; i++) { sum += source[i]; } return sum / source.Length; } /// /// Computes the average of values obtained by invoking a transform function on /// each element of the input array. /// /// The array to calculate the transformed average of. /// A transform function to apply to each element. /// The average of the array. public static decimal Average(this T[] source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); if (selector == null) throw new ArgumentNullException(nameof(selector)); decimal sum = 0; for (int i = 0; i < source.Length; i++) { sum += selector(source[i]); } return sum / source.Length; } // -------------------------- this SpanS -------------------------------------------- #if UNITY_2021_3_OR_NEWER /// /// Computes the average of an array /// /// The array to calculate the average of. /// The average of the array. public static double Average(this Span source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); long sum = 0; checked { for (int i = 0; i < source.Length; i++) { sum += source[i]; } } return (double)sum / source.Length; } /// /// Computes the average of values obtained by invoking a transform function on /// each element of the input array. /// /// The array to calculate the transformed average of. /// A transform function to apply to each element. /// The average of the array. public static double Average(this Span source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); if (selector == null) throw new ArgumentNullException(nameof(selector)); long sum = 0; checked { for (int i = 0; i < source.Length; i++) { sum += selector(source[i]); } } return (double)sum / source.Length; } /// /// Computes the average of an array /// /// The array to calculate the average of. /// The average of the array. public static double Average(this Span source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); long sum = 0; checked { for (int i = 0; i < source.Length; i++) { sum += source[i]; } } return (double)sum / source.Length; } /// /// Computes the average of values obtained by invoking a transform function on /// each element of the input array. /// /// The array to calculate the transformed average of. /// A transform function to apply to each element. /// The average of the array. public static double Average(this Span source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); if (selector == null) throw new ArgumentNullException(nameof(selector)); long sum = 0; checked { for (int i = 0; i < source.Length; i++) { sum += selector(source[i]); } } return (double)sum / source.Length; } /// /// Computes the average of an array /// /// The array to calculate the average of. /// The average of the array. public static float Average(this Span source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); double sum = 0; for (int i = 0; i < source.Length; i++) { sum += source[i]; } return (float)(sum / source.Length); } /// /// Computes the average of values obtained by invoking a transform function on /// each element of the input array. /// /// The array to calculate the transformed average of. /// A transform function to apply to each element. /// The average of the array. public static float Average(this Span source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); if (selector == null) throw new ArgumentNullException(nameof(selector)); double sum = 0; for (int i = 0; i < source.Length; i++) { sum += selector(source[i]); } return (float)(sum / source.Length); } /// /// Computes the average of an array /// /// The array to calculate the average of. /// The average of the array. public static double Average(this Span source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); double sum = 0; for (int i = 0; i < source.Length; i++) { sum += source[i]; } return sum / source.Length; } /// /// Computes the average of values obtained by invoking a transform function on /// each element of the input array. /// /// The array to calculate the transformed average of. /// A transform function to apply to each element. /// The average of the array. public static double Average(this Span source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); if (selector == null) throw new ArgumentNullException(nameof(selector)); double sum = 0; for (int i = 0; i < source.Length; i++) { sum += selector(source[i]); } return sum / source.Length; } /// /// Computes the average of an array /// /// The array to calculate the average of. /// The average of the array. public static decimal Average(this Span source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); decimal sum = 0; for (int i = 0; i < source.Length; i++) { sum += source[i]; } return sum / source.Length; } /// /// Computes the average of values obtained by invoking a transform function on /// each element of the input array. /// /// The array to calculate the transformed average of. /// A transform function to apply to each element. /// The average of the array. public static decimal Average(this Span source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); if (selector == null) throw new ArgumentNullException(nameof(selector)); decimal sum = 0; for (int i = 0; i < source.Length; i++) { sum += selector(source[i]); } return sum / source.Length; } #endif // -------------------------- Lists -------------------------------------------- /// /// Computes the average of a list. /// /// The list to calculate the average of. /// The average of the list. public static double Average(this List source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Count == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); long sum = 0; checked { for (int i = 0; i < source.Count; i++) { sum += source[i]; } } return (double)sum / source.Count; } /// /// Computes the average of values obtained by invoking a transform function on /// each element of the input array. /// /// The array to calculate the transformed average of. /// A transform function to apply to each element. /// The average of the array. public static double Average(this List source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Count == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); if (selector == null) throw new ArgumentNullException(nameof(selector)); long sum = 0; checked { for (int i = 0; i < source.Count; i++) { sum += selector(source[i]); } } return (double)sum / source.Count; } /// /// Computes the average of a list. /// /// The list to calculate the average of. /// The average of the list. public static double Average(this List source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Count == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); long sum = 0; checked { for (int i = 0; i < source.Count; i++) { sum += source[i]; } } return (double)sum / source.Count; } /// /// Computes the average of values obtained by invoking a transform function on /// each element of the input array. /// /// The array to calculate the transformed average of. /// A transform function to apply to each element. /// The average of the array. public static double Average(this List source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Count == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); if (selector == null) throw new ArgumentNullException(nameof(selector)); long sum = 0; checked { for (int i = 0; i < source.Count; i++) { sum += selector(source[i]); } } return (double)sum / source.Count; } /// /// Computes the average of a list. /// /// The list to calculate the average of. /// The average of the list. public static float Average(this List source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Count == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); double sum = 0; for (int i = 0; i < source.Count; i++) { sum += source[i]; } return (float)(sum / source.Count); } /// /// Computes the average of values obtained by invoking a transform function on /// each element of the input array. /// /// The array to calculate the transformed average of. /// A transform function to apply to each element. /// The average of the array. public static float Average(this List source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Count == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); if (selector == null) throw new ArgumentNullException(nameof(selector)); double sum = 0; for (int i = 0; i < source.Count; i++) { sum += selector(source[i]); } return (float)(sum / source.Count); } /// /// Computes the average of a list. /// /// The list to calculate the average of. /// The average of the list. public static double Average(this List source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Count == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); double sum = 0; for (int i = 0; i < source.Count; i++) { sum += source[i]; } return sum / source.Count; } /// /// Computes the average of values obtained by invoking a transform function on /// each element of the input array. /// /// The array to calculate the transformed average of. /// A transform function to apply to each element. /// The average of the array. public static double Average(this List source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Count == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); if (selector == null) throw new ArgumentNullException(nameof(selector)); double sum = 0; for (int i = 0; i < source.Count; i++) { sum += selector(source[i]); } return sum / source.Count; } /// /// Computes the average of a list. /// /// The list to calculate the average of. /// The average of the list. public static decimal Average(this List source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Count == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); decimal sum = 0; for (int i = 0; i < source.Count; i++) { sum += source[i]; } return sum / source.Count; } /// /// Computes the average of values obtained by invoking a transform function on /// each element of the input array. /// /// The array to calculate the transformed average of. /// A transform function to apply to each element. /// The average of the array. public static decimal Average(this List source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Count == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); if (selector == null) throw new ArgumentNullException(nameof(selector)); decimal sum = 0; for (int i = 0; i < source.Count; i++) { sum += selector(source[i]); } return sum / source.Count; } } } ================================================ FILE: VirtueSky/Linq/Average.cs.meta ================================================ fileFormatVersion: 2 guid: c05cbaf5747bb654fb7fbad5a184abfe MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Linq/Chunk.cs ================================================ using System; using System.Collections.Generic; namespace VirtueSky.Linq { public static partial class L { // -------------------------- ARRAYS -------------------------------------------- /// /// Splits the given sequence into chunks of the given size. /// If the sequence length isn't evenly divisible by the chunk size, /// the last chunk will contain all remaining elements. /// /// /// /// /// public static TSource[][] Chunk(this TSource[] source, int chunkSize) { if (source == null) throw new ArgumentNullException(nameof(source)); if (chunkSize <= 0) throw new ArgumentOutOfRangeException(nameof(chunkSize)); int size = source.Length / chunkSize; int extraSize = source.Length % chunkSize; if (extraSize != 0) size++; var result = new TSource[size][]; int currentIndex = 0; int indexChunk = 0; if (size != 0) { foreach (var element in source) { if (result[indexChunk] == null) { if (extraSize != 0 && indexChunk == size - 1) { result[indexChunk] = new TSource[extraSize]; } else { result[indexChunk] = new TSource[chunkSize]; } } result[indexChunk][currentIndex++] = element; if (currentIndex == chunkSize) { indexChunk++; currentIndex = 0; } } } return result; } // -------------------------- LISTS -------------------------------------------- /// /// Splits the given sequence into chunks of the given size. /// If the sequence length isn't evenly divisible by the chunk size, /// the last chunk will contain all remaining elements. /// /// /// /// /// public static List> Chunk(this List source, int chunkSize) { if (source == null) throw new ArgumentNullException(nameof(source)); if (chunkSize <= 0) throw new ArgumentOutOfRangeException(nameof(chunkSize)); int size = source.Count / chunkSize; int extraSize = source.Count % chunkSize; if (extraSize != 0) size++; var result = new List>(size); var currentIndex = 0; var indexChunk = 0; if (size != 0) { for (int i = 0; i < size; i++) { result.Add(new List()); } foreach (var element in source) { result[indexChunk] = result[indexChunk] ?? new List(); result[indexChunk].Add(element); currentIndex++; if (currentIndex == chunkSize) { indexChunk++; currentIndex = 0; } } } return result; } /// /// Splits the given sequence into chunks of the given size. /// If the sequence length isn't evenly divisible by the chunk size, /// the last chunk will contain all remaining elements. /// /// /// /// /// public static TSource[][] ChunkToArray(this List source, int chunkSize) { if (source == null) throw new ArgumentNullException(nameof(source)); if (chunkSize <= 0) throw new ArgumentOutOfRangeException(nameof(chunkSize)); int size = source.Count / chunkSize; int extraSize = source.Count % chunkSize; if (extraSize != 0) size++; var result = new TSource[size][]; int currentIndex = 0; int indexChunk = 0; if (size != 0) { foreach (var element in source) { if (result[indexChunk] == null) { if (extraSize != 0 && indexChunk == size - 1) { result[indexChunk] = new TSource[extraSize]; } else { result[indexChunk] = new TSource[chunkSize]; } } result[indexChunk][currentIndex++] = element; if (currentIndex == chunkSize) { indexChunk++; currentIndex = 0; } } } return result; } } } ================================================ FILE: VirtueSky/Linq/Chunk.cs.meta ================================================ fileFormatVersion: 2 guid: e508a8542516477caaedb478e17e9c08 timeCreated: 1664520886 ================================================ FILE: VirtueSky/Linq/Contains.cs ================================================ using System; using System.Collections.Generic; namespace VirtueSky.Linq { public static partial class L { // -------------------------- ARRAYS -------------------------------------------- /// /// Determines whether an array contains a specified element by using the /// provided IEqualityComparer. /// /// An array in which to locate a value. /// The value to locate. /// An equality comparer to compare values. /// true if the source sequence contains an element that has the specified value; otherwise, false. public static bool Contains(this TSource[] source, TSource value, IEqualityComparer comparer = null) { if (source == null) throw new ArgumentNullException(nameof(source)); if (comparer == null) return Array.IndexOf(source, value) != -1; foreach (TSource e in source) { if (comparer.Equals(e, value)) { return true; } } return false; } // -------------------------- this SpanS -------------------------------------------- #if UNITY_2021_3_OR_NEWER /// /// Determines whether an array contains a specified element by using the /// provided IEqualityComparer. /// /// An array in which to locate a value. /// The value to locate. /// An equality comparer to compare values. /// true if the source sequence contains an element that has the specified value; otherwise, false. public static bool Contains(this Span source, TSource value, IEqualityComparer comparer = null) { if (source == null) throw new ArgumentNullException(nameof(source)); if (comparer == null) comparer = EqualityComparer.Default; for (int i = 0; i < source.Length; i++) { if (comparer.Equals(source[i], value)) { return true; } } return false; } #endif // -------------------------- Lists -------------------------------------------- /// /// Determines whether a list contains a specified element by using the /// provided IEqualityComparer. /// /// A list in which to locate a value. /// The value to locate. /// An equality comparer to compare values. /// true if the source sequence contains an element that has the specified value; otherwise, false. public static bool Contains(this List source, TSource value, IEqualityComparer comparer = null) { if (source == null) throw new ArgumentNullException(nameof(source)); if (comparer == null) return source.IndexOf(value) != -1; for (int i = 0; i < source.Count; i++) { if (comparer.Equals(source[i], value)) { return true; } } return false; } } } ================================================ FILE: VirtueSky/Linq/Contains.cs.meta ================================================ fileFormatVersion: 2 guid: 24b2f9dba1b94ef45a66fa604d7154a5 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Linq/Count.cs ================================================ using System; using System.Collections.Generic; namespace VirtueSky.Linq { public static partial class L { // -------------------------- Arrays -------------------------------------------- /// /// Returns a number that represents how many elements in the specified /// array satisfy a condition. /// /// An array that contains elements to be tested and counted. /// A function to test each element for a condition. /// A number that represents how many elements in the array satisfy the condition /// in the predicate function. public static int Count(this T[] source, Func predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); int count = 0; for (int i = 0; i < source.Length; i++) { checked { if (predicate(source[i])) { count++; } } } return count; } // -------------------------- this Spans -------------------------------------------- #if UNITY_2021_3_OR_NEWER /// /// Returns a number that represents how many elements in the specified /// array satisfy a condition. /// /// An array that contains elements to be tested and counted. /// A function to test each element for a condition. /// A number that represents how many elements in the array satisfy the condition /// in the predicate function. public static int Count(this Span source, Func predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); int count = 0; for (int i = 0; i < source.Length; i++) { checked { if (predicate(source[i])) { count++; } } } return count; } #endif // ------------------------------ Lists --------------------- /// /// Returns a number that represents how many elements in the specified /// list satisfy a condition. /// /// A list that contains elements to be tested and counted. /// A function to test each element for a condition. /// A number that represents how many elements in the list satisfy the condition /// in the predicate function. public static int Count(this List source, Func predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); int count = 0; for (int i = 0; i < source.Count; i++) { checked { if (predicate(source[i])) { count++; } } } return count; } } } ================================================ FILE: VirtueSky/Linq/Count.cs.meta ================================================ fileFormatVersion: 2 guid: 3aaa52a419914b34eb3def88aab913e0 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Linq/Distinct.cs ================================================ using System; using System.Collections.Generic; namespace VirtueSky.Linq { public static partial class L { public static IEnumerable Distinct(this IEnumerable source) { return System.Linq.Enumerable.Distinct(source); } public static IEnumerable Distinct(this IEnumerable source, IEqualityComparer comparer) { return System.Linq.Enumerable.Distinct(source, comparer); } public static System.Linq.ParallelQuery Distinct(this System.Linq.ParallelQuery source) { return System.Linq.ParallelEnumerable.Distinct(source); } public static System.Linq.ParallelQuery Distinct(this System.Linq.ParallelQuery source, IEqualityComparer comparer) { return System.Linq.ParallelEnumerable.Distinct(source, comparer); } /// /// Returns distinct elements from the given sequence using the default equality comparer /// to compare values projected by . /// /// The type of the elements of . /// The type of the projected value for each element of the sequence. /// The sequence. /// The projection that is applied to each element to retrieve the value which is being compared. /// A sequence of elements whose projected values are distinct. public static IEnumerable Distinct(this IEnumerable source, Func projection) { if (source == null) throw new ArgumentNullException(nameof(source)); if (projection == null) throw new ArgumentNullException(nameof(projection)); return DistinctIterator(source, projection, EqualityComparer.Default); } /// /// Returns distinct elements from the given sequence using the specified equality comparer /// to compare values projected by . /// /// The type of the elements of . /// The type of the projected value for each element of the sequence. /// The sequence. /// The projection that is applied to each element to retrieve the value which is being compared. /// The equality comparer to use for comparing the projected values. /// A sequence of elements whose projected values are considered distinct by the specified equality comparer. public static IEnumerable Distinct( this IEnumerable source, Func projection, IEqualityComparer equalityComparer) { if (source == null) throw new ArgumentNullException(nameof(source)); if (projection == null) throw new ArgumentNullException(nameof(projection)); if (equalityComparer == null) throw new ArgumentNullException(nameof(equalityComparer)); return DistinctIterator(source, projection, equalityComparer); } private static IEnumerable DistinctIterator( IEnumerable source, Func projection, IEqualityComparer equalityComparer) { var alreadySeenValues = new HashSet(equalityComparer); foreach (var element in source) { var value = projection(element); if (alreadySeenValues.Contains(value)) { continue; } yield return element; alreadySeenValues.Add(value); } } } } ================================================ FILE: VirtueSky/Linq/Distinct.cs.meta ================================================ fileFormatVersion: 2 guid: df53bfa4cfe4fda4fa8a6ccd414efa0a MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Linq/First.cs ================================================ using System; using System.Collections.Generic; namespace VirtueSky.Linq { public static partial class L { // -------------------------- Arrays -------------------------------------------- /// /// Returns the first element of an array. /// /// The array to return the first element of. /// The first element in the specified array. public static T First(this T[] source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); return source[0]; } /// /// Returns the first element in an array that satisfies a specified condition. /// /// An array to return an element from. /// A function to teast each element for a condition. /// The first element that satisfies the condition. public static T First(this T[] source, Func predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); for (int i = 0; i < source.Length; i++) { if (predicate(source[i])) { return source[i]; } } throw new InvalidOperationException("Sequence contains no matching element"); } /// /// Returns the first element of an array, or a default value if the /// array contains no elements. /// /// The array to return the first element of. /// default value if source is empty, otherwise, the first element /// in source. public static T FirstOrDefault(this T[] source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) return default; return source[0]; } /// /// Returns the first element of the sequence that satisfies a condition or a /// default value if no such element is found. /// /// An IEnumerable to return an element from. /// A function to test each element for a condition. /// public static T FirstOrDefault(this T[] source, Func predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); for (int i = 0; i < source.Length; i++) { if (predicate(source[i])) { return source[i]; } } return default; } // -------------------------- this Span -------------------------------------------- #if UNITY_2021_3_OR_NEWER /// /// Returns the first element of an array. /// /// The array to return the first element of. /// The first element in the specified array. public static T First(this Span source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); return source[0]; } /// /// Returns the first element in an array that satisfies a specified condition. /// /// An array to return an element from. /// A function to teast each element for a condition. /// The first element that satisfies the condition. public static T First(this Span source, Func predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); for (int i = 0; i < source.Length; i++) { if (predicate(source[i])) { return source[i]; } } throw new InvalidOperationException("Sequence contains no matching element"); } /// /// Returns the first element of an array, or a default value if the /// array contains no elements. /// /// The array to return the first element of. /// default value if source is empty, otherwise, the first element /// in source. public static T FirstOrDefault(this Span source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) return default; return source[0]; } /// /// Returns the first element of the sequence that satisfies a condition or a /// default value if no such element is found. /// /// An IEnumerable to return an element from. /// A function to test each element for a condition. /// public static T FirstOrDefault(this Span source, Func predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); for (int i = 0; i < source.Length; i++) { if (predicate(source[i])) { return source[i]; } } return default; } #endif // -------------------------- Lists -------------------------------------------- /// /// Returns the first element of a list /// /// The list to return the first element of. /// The first element in the specified list. public static T First(this List source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Count == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); return source[0]; } /// /// Returns the first element in a list that satisfies a specified condition. /// /// An list to return an element from. /// A function to teast each element for a condition. /// The first element in the list that satisfies the condition. public static T First(this List source, Predicate predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); var firstIndex = source.FindIndex(predicate); if (firstIndex == -1) throw new InvalidOperationException("Sequence contains no matching element"); return source[firstIndex]; } /// /// Returns the first element of an array, or a default value if the /// array contains no elements. /// /// The array to return the first element of. /// default value if source is empty, otherwise, the first element /// in source. public static T FirstOrDefault(this List source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Count == 0) return default; return source[0]; } /// /// Returns the first element of the sequence that satisfies a condition or a /// default value if no such element is found. /// /// An IEnumerable to return an element from. /// A function to test each element for a condition. /// public static T FirstOrDefault(this List source, Predicate predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); var firstIndex = source.FindIndex(predicate); if (firstIndex == -1) return default; return source[firstIndex]; } } } ================================================ FILE: VirtueSky/Linq/First.cs.meta ================================================ fileFormatVersion: 2 guid: 8c1d92ed50ac2284d8e1dbeddda1f1d1 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Linq/Flatten.cs ================================================ using System; using System.Collections.Generic; namespace VirtueSky.Linq { public static partial class L { // -------------------------- ARRAYS -------------------------------------------- /// /// Returns a flattened sequence that contains the concatenation of all the nested sequences' elements. /// /// The type of the elements of . /// A sequence of sequences to be flattened. /// The concatenation of all the nested sequences' elements. public static TSource[] Flatten(this TSource[][] source) { if (source == null) throw new ArgumentNullException(nameof(source)); var result = new List(); foreach (var array in source) { foreach (var s1 in array) { result.Add(s1); } } return result.ToArray(); } // -------------------------- LISTS -------------------------------------------- // -------------------------- ARRAYS -------------------------------------------- /// /// Returns a flattened sequence that contains the concatenation of all the nested sequences' elements. /// /// The type of the elements of . /// A sequence of sequences to be flattened. /// The concatenation of all the nested sequences' elements. public static List Flatten(this List> source) { if (source == null) throw new ArgumentNullException(nameof(source)); var result = new List(); foreach (var array in source) { for (var i = 0; i < array.Count; i++) { result.Add(array[i]); } } return result; } /// /// Returns a flattened sequence that contains the concatenation of all the nested sequences' elements. /// /// The type of the elements of . /// A sequence of sequences to be flattened. /// The concatenation of all the nested sequences' elements. public static List Flatten(this List source) { if (source == null) throw new ArgumentNullException(nameof(source)); var result = new List(); foreach (var array in source) { foreach (var s1 in array) { result.Add(s1); } } return result; } } } ================================================ FILE: VirtueSky/Linq/Flatten.cs.meta ================================================ fileFormatVersion: 2 guid: e893bfd4dd584645830be4eff1d00e33 timeCreated: 1664529405 ================================================ FILE: VirtueSky/Linq/Last.cs ================================================ using System; using System.Collections.Generic; namespace VirtueSky.Linq { public static partial class L { // -------------------------- Arrays -------------------------------------------- /// /// Returns the last element of a sequence. /// /// An sequence to return the last element of. /// The value at the last position in the source sequence. public static T Last(this T[] source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); return source[source.Length - 1]; } /// /// Returns the last element of a sequence that satisfies a specified condition. /// /// A sequence to return an element from. /// A function to test each element for a condition. /// public static T Last(this T[] source, Predicate predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); var lastIndex = Array.FindLastIndex(source, predicate); if (lastIndex == -1) throw new InvalidOperationException("Sequence contains no matching element"); return source[lastIndex]; } /// /// Returns the last element of a sequence, or a default value if the sequence contains no elements. /// /// An sequence to return the last element of. /// default value if the source sequence is empty; otherwise, /// the last element in the sequence public static T LastOrDefault(this T[] source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) { return default; } return source[source.Length - 1]; } /// /// Returns the last element of a sequence that satisfies a condition or a default value if no such element is found. /// /// A sequence to return the last element of. /// A function to test each element for a condition. /// default value if the sequence is empty or if no elements pass the test /// in the predicate function; otherwise, the last element that passes the test in the /// predicate function. public static T LastOrDefault(this T[] source, Predicate predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); var lastIndex = Array.FindLastIndex(source, predicate); if (lastIndex == -1) return default; return source[lastIndex]; } // -------------------------- this Spans -------------------------------------------- #if UNITY_2021_3_OR_NEWER /// /// Returns the last element of a sequence. /// /// An sequence to return the last element of. /// The value at the last position in the source sequence. public static T Last(this Span source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); return source[source.Length - 1]; } /// /// Returns the last element of a sequence that satisfies a specified condition. /// /// A sequence to return an element from. /// A function to test each element for a condition. /// public static T Last(this Span source, Predicate predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); for (int i = source.Length - 1; i >= 0; i--) { if (predicate(source[i])) return source[i]; } throw new InvalidOperationException("Sequence contains no matching element"); } /// /// Returns the last element of a sequence, or a default value if the sequence contains no elements. /// /// An sequence to return the last element of. /// default value if the source sequence is empty; otherwise, /// the last element in the sequence public static T LastOrDefault(this Span source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) { return default; } return source[source.Length - 1]; } /// /// Returns the last element of a sequence that satisfies a condition or a default value if no such element is found. /// /// A sequence to return the last element of. /// A function to test each element for a condition. /// default value if the sequence is empty or if no elements pass the test /// in the predicate function; otherwise, the last element that passes the test in the /// predicate function. public static T LastOrDefault(this Span source, Predicate predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); for (int i = source.Length - 1; i >= 0; i--) { if (predicate(source[i])) return source[i]; } return default; } #endif // -------------------------- Lists -------------------------------------------- /// /// Returns the last element of a sequence. /// /// An sequence to return the last element of. /// The value at the last position in the source sequence. public static T Last(this List source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Count == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); return source[source.Count - 1]; } /// /// Returns the last element of a sequence that satisfies a specified condition. /// /// A sequence to return an element from. /// A function to test each element for a condition. /// public static T Last(this List source, Predicate predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); var lastIndex = source.FindLastIndex(predicate); if (lastIndex == -1) throw new InvalidOperationException("Sequence contains no matching element"); return source[lastIndex]; } /// /// Returns the last element of a sequence, or a default value if the sequence contains no elements. /// /// An sequence to return the last element of. /// default value if the source sequence is empty; otherwise, /// the last element in the sequence public static T LastOrDefault(this List source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Count == 0) { return default; } return source[source.Count - 1]; } /// /// Returns the last element of a sequence that satisfies a condition or a default value if no such element is found. /// /// A sequence to return the last element of. /// A function to test each element for a condition. /// default value if the sequence is empty or if no elements pass the test /// in the predicate function; otherwise, the last element that passes the test in the /// predicate function. public static T LastOrDefault(this List source, Predicate predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); var lastIndex = source.FindLastIndex(predicate); if (lastIndex == -1) return default; return source[lastIndex]; } } } ================================================ FILE: VirtueSky/Linq/Last.cs.meta ================================================ fileFormatVersion: 2 guid: 6bc600c7bc78bb244bf70dc75dd15fb8 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Linq/Max.cs ================================================ using System; using System.Collections.Generic; namespace VirtueSky.Linq { //int, long, float,double, decimal public static partial class L { // -------------------------- ARRAYS -------------------------------------------- /// /// Returns the maximum value in a sequence of values. /// /// A sequence of values to determine the maximum of. /// The maximum value in the sequence public static T Max(this T[] source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); Comparer comparer = Comparer.Default; T r = default(T); if (r == null) { r = source[0]; for (int i = 1; i < source.Length; i++) { if (source[i] != null && comparer.Compare(source[i], r) > 0) r = source[i]; } } else { r = source[0]; for (int i = 1; i < source.Length; i++) { if (comparer.Compare(source[i], r) > 0) r = source[i]; } } return r; } /// /// Invokes a transform function on each element of a sequence and returns the maximum value. /// /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The maximum value in the transform of the sequence. public static TResult Max(this T[] source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (selector == null) throw new ArgumentNullException(nameof(selector)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); Comparer comparer = Comparer.Default; TResult r = default(TResult); if (r == null) { r = selector(source[0]); for (int i = 1; i < source.Length; i++) { var v = selector(source[i]); if (v != null && comparer.Compare(v, r) > 0) r = v; } } else { r = selector(source[0]); for (int i = 1; i < source.Length; i++) { var v = selector(source[i]); if (comparer.Compare(v, r) > 0) r = v; } } return r; } /// /// Returns the maximum value in a sequence of values. /// /// A sequence of values to determine the maximum of. /// The maximum value in the sequence public static int Max(this int[] source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); int r = int.MinValue; for (int i = 0; i < source.Length; i++) { if (source[i] > r) r = source[i]; } return r; } /// /// Invokes a transform function on each element of a sequence and returns the maximum value. /// /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The maximum value in the transform of the sequence. public static int Max(this T[] source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); if (selector == null) throw new ArgumentNullException(nameof(selector)); int r = int.MinValue; for (int i = 0; i < source.Length; i++) { var v = selector(source[i]); if (v > r) r = v; } return r; } /// /// Returns the maximum value in a sequence of values. /// /// A sequence of values to determine the maximum of. /// The maximum value in the sequence public static long Max(this long[] source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); long r = long.MinValue; for (int i = 0; i < source.Length; i++) { if (source[i] > r) r = source[i]; } return r; } /// /// Invokes a transform function on each element of a sequence and returns the maximum value. /// /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The maximum value in the transform of the sequence. public static long Max(this T[] source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); if (selector == null) throw new ArgumentNullException(nameof(selector)); long r = long.MinValue; for (int i = 0; i < source.Length; i++) { var v = selector(source[i]); if (v > r) r = v; } return r; } /// /// Returns the maximum value in a sequence of values. /// /// A sequence of values to determine the maximum of. /// The maximum value in the sequence public static float Max(this float[] source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); float r = source[0]; int startIndex = 0; for (; startIndex < source.Length; startIndex++) { if (!float.IsNaN(source[startIndex])) { r = source[startIndex]; break; } } for (int i = startIndex; i < source.Length; i++) { if (source[i] > r) r = source[i]; } return r; } /// /// Invokes a transform function on each element of a sequence and returns the maximum value. /// /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The maximum value in the transform of the sequence. public static float Max(this T[] source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); if (selector == null) throw new ArgumentNullException(nameof(selector)); float r = selector(source[0]); int startIndex = 0; for (; startIndex < source.Length; startIndex++) { var v = selector(source[startIndex]); if (!float.IsNaN(v)) { r = v; break; } } for (int i = startIndex; i < source.Length; i++) { var v = selector(source[i]); if (v > r) r = v; } return r; } /// /// Returns the maximum value in a sequence of values. /// /// A sequence of values to determine the maximum of. /// The maximum value in the sequence public static double Max(this double[] source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); double r = source[0]; int startIndex = 0; for (; startIndex < source.Length; startIndex++) { if (!double.IsNaN(source[startIndex])) { r = source[startIndex]; break; } } for (int i = startIndex; i < source.Length; i++) { if (source[i] > r) r = source[i]; } return r; } /// /// Invokes a transform function on each element of a sequence and returns the maximum value. /// /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The maximum value in the transform of the sequence. public static double Max(this T[] source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); if (selector == null) throw new ArgumentNullException(nameof(selector)); double r = selector(source[0]); int startIndex = 0; for (; startIndex < source.Length; startIndex++) { var v = selector(source[startIndex]); if (!double.IsNaN(v)) { r = v; break; } } for (int i = startIndex; i < source.Length; i++) { var v = selector(source[i]); if (v > r) r = v; } return r; } /// /// Returns the maximum value in a sequence of values. /// /// A sequence of values to determine the maximum of. /// The maximum value in the sequence public static decimal Max(this decimal[] source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); decimal r = decimal.MinValue; for (int i = 0; i < source.Length; i++) { if (source[i] > r) r = source[i]; } return r; } /// /// Invokes a transform function on each element of a sequence and returns the maximum value. /// /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The maximum value in the transform of the sequence. public static decimal Max(this T[] source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); if (selector == null) throw new ArgumentNullException(nameof(selector)); decimal r = decimal.MinValue; for (int i = 0; i < source.Length; i++) { var v = selector(source[i]); if (v > r) r = v; } return r; } // -------------------------- this Spans -------------------------------------------- #if UNITY_2021_3_OR_NEWER /// /// Returns the maximum value in a sequence of values. /// /// A sequence of values to determine the maximum of. /// The maximum value in the sequence public static T Max(this Span source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); Comparer comparer = Comparer.Default; T r = default(T); if (r == null) { r = source[0]; for (int i = 1; i < source.Length; i++) { if (source[i] != null && comparer.Compare(source[i], r) > 0) r = source[i]; } } else { r = source[0]; for (int i = 1; i < source.Length; i++) { if (comparer.Compare(source[i], r) > 0) r = source[i]; } } return r; } /// /// Invokes a transform function on each element of a sequence and returns the maximum value. /// /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The maximum value in the transform of the sequence. public static TResult Max(this Span source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (selector == null) throw new ArgumentNullException(nameof(selector)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); Comparer comparer = Comparer.Default; TResult r = default(TResult); if (r == null) { r = selector(source[0]); for (int i = 1; i < source.Length; i++) { var v = selector(source[i]); if (v != null && comparer.Compare(v, r) > 0) r = v; } } else { r = selector(source[0]); for (int i = 1; i < source.Length; i++) { var v = selector(source[i]); if (comparer.Compare(v, r) > 0) r = v; } } return r; } /// /// Returns the maximum value in a sequence of values. /// /// A sequence of values to determine the maximum of. /// The maximum value in the sequence public static int Max(this Span source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); int r = int.MinValue; for (int i = 0; i < source.Length; i++) { if (source[i] > r) r = source[i]; } return r; } /// /// Invokes a transform function on each element of a sequence and returns the maximum value. /// /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The maximum value in the transform of the sequence. public static int Max(this Span source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); if (selector == null) throw new ArgumentNullException(nameof(selector)); int r = int.MinValue; for (int i = 0; i < source.Length; i++) { var v = selector(source[i]); if (v > r) r = v; } return r; } /// /// Returns the maximum value in a sequence of values. /// /// A sequence of values to determine the maximum of. /// The maximum value in the sequence public static long Max(this Span source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); long r = long.MinValue; for (int i = 0; i < source.Length; i++) { if (source[i] > r) r = source[i]; } return r; } /// /// Invokes a transform function on each element of a sequence and returns the maximum value. /// /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The maximum value in the transform of the sequence. public static long Max(this Span source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); if (selector == null) throw new ArgumentNullException(nameof(selector)); long r = long.MinValue; for (int i = 0; i < source.Length; i++) { var v = selector(source[i]); if (v > r) r = v; } return r; } /// /// Returns the maximum value in a sequence of values. /// /// A sequence of values to determine the maximum of. /// The maximum value in the sequence public static float Max(this Span source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); float r = source[0]; int startIndex = 0; for (; startIndex < source.Length; startIndex++) { if (!float.IsNaN(source[startIndex])) { r = source[startIndex]; break; } } for (int i = startIndex; i < source.Length; i++) { if (source[i] > r) r = source[i]; } return r; } /// /// Invokes a transform function on each element of a sequence and returns the maximum value. /// /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The maximum value in the transform of the sequence. public static float Max(this Span source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); if (selector == null) throw new ArgumentNullException(nameof(selector)); float r = selector(source[0]); int startIndex = 0; for (; startIndex < source.Length; startIndex++) { var v = selector(source[startIndex]); if (!float.IsNaN(v)) { r = v; break; } } for (int i = startIndex; i < source.Length; i++) { var v = selector(source[i]); if (v > r) r = v; } return r; } /// /// Returns the maximum value in a sequence of values. /// /// A sequence of values to determine the maximum of. /// The maximum value in the sequence public static double Max(this Span source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); double r = source[0]; int startIndex = 0; for (; startIndex < source.Length; startIndex++) { if (!double.IsNaN(source[startIndex])) { r = source[startIndex]; break; } } for (int i = startIndex; i < source.Length; i++) { if (source[i] > r) r = source[i]; } return r; } /// /// Invokes a transform function on each element of a sequence and returns the maximum value. /// /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The maximum value in the transform of the sequence. public static double Max(this Span source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); if (selector == null) throw new ArgumentNullException(nameof(selector)); double r = selector(source[0]); int startIndex = 0; for (; startIndex < source.Length; startIndex++) { var v = selector(source[startIndex]); if (!double.IsNaN(v)) { r = v; break; } } for (int i = startIndex; i < source.Length; i++) { var v = selector(source[i]); if (v > r) r = v; } return r; } /// /// Returns the maximum value in a sequence of values. /// /// A sequence of values to determine the maximum of. /// The maximum value in the sequence public static decimal Max(this Span source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); decimal r = decimal.MinValue; for (int i = 0; i < source.Length; i++) { if (source[i] > r) r = source[i]; } return r; } /// /// Invokes a transform function on each element of a sequence and returns the maximum value. /// /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The maximum value in the transform of the sequence. public static decimal Max(this Span source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); if (selector == null) throw new ArgumentNullException(nameof(selector)); decimal r = decimal.MinValue; for (int i = 0; i < source.Length; i++) { var v = selector(source[i]); if (v > r) r = v; } return r; } #endif // -------------------------- LISTS -------------------------------------------- /// /// Returns the maximum value in a sequence of values. /// /// A sequence of values to determine the maximum of. /// The maximum value in the sequence public static T Max(this List source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Count == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); Comparer comparer = Comparer.Default; T r = default(T); if (r == null) { r = source[0]; for (int i = 1; i < source.Count; i++) { if (source[i] != null && comparer.Compare(source[i], r) > 0) r = source[i]; } } else { r = source[0]; for (int i = 1; i < source.Count; i++) { if (comparer.Compare(source[i], r) > 0) r = source[i]; } } return r; } /// /// Invokes a transform function on each element of a sequence and returns the maximum value. /// /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The maximum value in the transform of the sequence. public static TResult Max(this List source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (selector == null) throw new ArgumentNullException(nameof(selector)); if (source.Count == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); Comparer comparer = Comparer.Default; TResult r = default(TResult); if (r == null) { r = selector(source[0]); for (int i = 1; i < source.Count; i++) { var v = selector(source[i]); if (v != null && comparer.Compare(v, r) > 0) r = v; } } else { r = selector(source[0]); for (int i = 1; i < source.Count; i++) { var v = selector(source[i]); if (comparer.Compare(v, r) > 0) r = v; } } return r; } /// /// Returns the maximum value in a sequence of values. /// /// A sequence of values to determine the maximum of. /// The maximum value in the sequence public static int Max(this List source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Count == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); int r = int.MinValue; for (int i = 0; i < source.Count; i++) { if (source[i] > r) r = source[i]; } return r; } /// /// Invokes a transform function on each element of a sequence and returns the maximum value. /// /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The maximum value in the transform of the sequence. public static int Max(this List source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Count == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); if (selector == null) throw new ArgumentNullException(nameof(selector)); int r = int.MinValue; for (int i = 0; i < source.Count; i++) { var v = selector(source[i]); if (v > r) r = v; } return r; } /// /// Returns the maximum value in a sequence of values. /// /// A sequence of values to determine the maximum of. /// The maximum value in the sequence public static long Max(this List source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Count == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); long r = long.MinValue; for (int i = 0; i < source.Count; i++) { if (source[i] > r) r = source[i]; } return r; } /// /// Invokes a transform function on each element of a sequence and returns the maximum value. /// /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The maximum value in the transform of the sequence. public static long Max(this List source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Count == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); if (selector == null) throw new ArgumentNullException(nameof(selector)); long r = long.MinValue; for (int i = 0; i < source.Count; i++) { var v = selector(source[i]); if (v > r) r = v; } return r; } /// /// Returns the maximum value in a sequence of values. /// /// A sequence of values to determine the maximum of. /// The maximum value in the sequence public static float Max(this List source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Count == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); float r = source[0]; int startIndex = 0; for (; startIndex < source.Count; startIndex++) { if (!float.IsNaN(source[startIndex])) { r = source[startIndex]; break; } } for (int i = startIndex; i < source.Count; i++) { if (source[i] > r) r = source[i]; } return r; } /// /// Invokes a transform function on each element of a sequence and returns the maximum value. /// /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The maximum value in the transform of the sequence. public static float Max(this List source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Count == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); if (selector == null) throw new ArgumentNullException(nameof(selector)); float r = selector(source[0]); int startIndex = 0; for (; startIndex < source.Count; startIndex++) { var v = selector(source[startIndex]); if (!float.IsNaN(v)) { r = v; break; } } for (int i = startIndex; i < source.Count; i++) { var v = selector(source[i]); if (v > r) r = v; } return r; } /// /// Returns the maximum value in a sequence of values. /// /// A sequence of values to determine the maximum of. /// The maximum value in the sequence public static double Max(this List source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Count == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); double r = source[0]; int startIndex = 0; for (; startIndex < source.Count; startIndex++) { if (!double.IsNaN(source[startIndex])) { r = source[startIndex]; break; } } for (int i = startIndex; i < source.Count; i++) { if (source[i] > r) r = source[i]; } return r; } /// /// Invokes a transform function on each element of a sequence and returns the maximum value. /// /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The maximum value in the transform of the sequence. public static double Max(this List source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Count == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); if (selector == null) throw new ArgumentNullException(nameof(selector)); double r = selector(source[0]); int startIndex = 0; for (; startIndex < source.Count; startIndex++) { var v = selector(source[startIndex]); if (!double.IsNaN(v)) { r = v; break; } } for (int i = startIndex; i < source.Count; i++) { var v = selector(source[i]); if (v > r) r = v; } return r; } /// /// Returns the maximum value in a sequence of values. /// /// A sequence of values to determine the maximum of. /// The maximum value in the sequence public static decimal Max(this List source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Count == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); decimal r = decimal.MinValue; for (int i = 0; i < source.Count; i++) { if (source[i] > r) r = source[i]; } return r; } /// /// Invokes a transform function on each element of a sequence and returns the maximum value. /// /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The maximum value in the transform of the sequence. public static decimal Max(this List source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Count == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); decimal r = decimal.MinValue; for (int i = 0; i < source.Count; i++) { var v = selector(source[i]); if (v > r) r = v; } return r; } } } ================================================ FILE: VirtueSky/Linq/Max.cs.meta ================================================ fileFormatVersion: 2 guid: 5a7be0bf1dc94a745a794b9c63d53b42 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Linq/Min.cs ================================================ using System; using System.Collections.Generic; namespace VirtueSky.Linq { //int, long, float,double, decimal public static partial class L { // -------------------------- ARRAYS -------------------------------------------- /// /// Returns the minimum value in a sequence of values. /// /// A sequence of values to determine the minimum of. /// The minimum value in the sequence public static T Min(this T[] source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); Comparer comparer = Comparer.Default; T r = default(T); if (r == null) { r = source[0]; for (int i = 1; i < source.Length; i++) { if (source[i] != null && comparer.Compare(source[i], r) < 0) r = source[i]; } } else { r = source[0]; for (int i = 1; i < source.Length; i++) { if (comparer.Compare(source[i], r) < 0) r = source[i]; } } return r; } /// /// Invokes a transform function on each element of a sequence and returns the maximum value. /// /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The maximum value in the transform of the sequence. public static TResult Min(this T[] source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (selector == null) throw new ArgumentNullException(nameof(selector)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); Comparer comparer = Comparer.Default; TResult r = default(TResult); if (r == null) { r = selector(source[0]); for (int i = 1; i < source.Length; i++) { var v = selector(source[i]); if (v != null && comparer.Compare(v, r) < 0) r = v; } } else { r = selector(source[0]); for (int i = 1; i < source.Length; i++) { var v = selector(source[i]); if (comparer.Compare(v, r) < 0) r = v; } } return r; } /// /// Returns the minimum value in a sequence of values. /// /// A sequence of values to determine the minimum of. /// The minimum value in the sequence public static int Min(this int[] source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); int r = int.MaxValue; for (int i = 0; i < source.Length; i++) { if (source[i] < r) r = source[i]; } return r; } /// /// Invokes a transform function on each element of a sequence and returns the maximum value. /// /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The maximum value in the transform of the sequence. public static int Min(this T[] source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); if (selector == null) throw new ArgumentNullException(nameof(selector)); int r = int.MaxValue; for (int i = 0; i < source.Length; i++) { var v = selector(source[i]); if (v < r) r = v; } return r; } /// /// Returns the minimum value in a sequence of values. /// /// A sequence of values to determine the minimum of. /// The minimum value in the sequence public static long Min(this long[] source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); long r = long.MaxValue; for (int i = 0; i < source.Length; i++) { if (source[i] < r) r = source[i]; } return r; } /// /// Invokes a transform function on each element of a sequence and returns the maximum value. /// /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The maximum value in the transform of the sequence. public static long Min(this T[] source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); if (selector == null) throw new ArgumentNullException(nameof(selector)); long r = long.MaxValue; for (int i = 0; i < source.Length; i++) { var v = selector(source[i]); if (v < r) r = v; } return r; } /// /// Returns the minimum value in a sequence of values. /// /// A sequence of values to determine the minimum of. /// The minimum value in the sequence public static float Min(this float[] source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); float r = float.MaxValue; for (int i = 0; i < source.Length; i++) { if (source[i] < r) r = source[i]; else if (float.IsNaN(source[i])) return source[i]; } return r; } /// /// Invokes a transform function on each element of a sequence and returns the maximum value. /// /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The maximum value in the transform of the sequence. public static float Min(this T[] source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); if (selector == null) throw new ArgumentNullException(nameof(selector)); float r = float.MaxValue; for (int i = 0; i < source.Length; i++) { var v = selector(source[i]); if (v < r) r = v; else if (float.IsNaN(v)) return v; } return r; } /// /// Returns the minimum value in a sequence of values. /// /// A sequence of values to determine the minimum of. /// The minimum value in the sequence public static double Min(this double[] source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); double r = double.MaxValue; for (int i = 0; i < source.Length; i++) { if (source[i] < r) r = source[i]; else if (double.IsNaN(source[i])) return source[i]; } return r; } /// /// Invokes a transform function on each element of a sequence and returns the maximum value. /// /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The maximum value in the transform of the sequence. public static double Min(this T[] source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); if (selector == null) throw new ArgumentNullException(nameof(selector)); double r = double.MaxValue; for (int i = 0; i < source.Length; i++) { var v = selector(source[i]); if (v < r) r = v; else if (double.IsNaN(v)) return v; } return r; } /// /// Returns the minimum value in a sequence of values. /// /// A sequence of values to determine the minimum of. /// The minimum value in the sequence public static decimal Min(this decimal[] source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); decimal r = decimal.MaxValue; for (int i = 0; i < source.Length; i++) { if (source[i] < r) r = source[i]; } return r; } /// /// Invokes a transform function on each element of a sequence and returns the maximum value. /// /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The maximum value in the transform of the sequence. public static decimal Min(this T[] source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); if (selector == null) throw new ArgumentNullException(nameof(selector)); decimal r = decimal.MaxValue; for (int i = 0; i < source.Length; i++) { var v = selector(source[i]); if (v < r) r = v; } return r; } // -------------------------- this Spans -------------------------------------------- #if UNITY_2021_3_OR_NEWER /// /// Returns the minimum value in a sequence of values. /// /// A sequence of values to determine the minimum of. /// The minimum value in the sequence public static T Min(this Span source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); Comparer comparer = Comparer.Default; T r = default(T); if (r == null) { r = source[0]; for (int i = 1; i < source.Length; i++) { if (source[i] != null && comparer.Compare(source[i], r) < 0) r = source[i]; } } else { r = source[0]; for (int i = 1; i < source.Length; i++) { if (comparer.Compare(source[i], r) < 0) r = source[i]; } } return r; } /// /// Invokes a transform function on each element of a sequence and returns the maximum value. /// /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The maximum value in the transform of the sequence. public static TResult Min(this Span source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (selector == null) throw new ArgumentNullException(nameof(selector)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); Comparer comparer = Comparer.Default; TResult r = default(TResult); if (r == null) { r = selector(source[0]); for (int i = 1; i < source.Length; i++) { var v = selector(source[i]); if (v != null && comparer.Compare(v, r) < 0) r = v; } } else { r = selector(source[0]); for (int i = 1; i < source.Length; i++) { var v = selector(source[i]); if (comparer.Compare(v, r) < 0) r = v; } } return r; } /// /// Returns the minimum value in a sequence of values. /// /// A sequence of values to determine the minimum of. /// The minimum value in the sequence public static int Min(this Span source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); int r = int.MaxValue; for (int i = 0; i < source.Length; i++) { if (source[i] < r) r = source[i]; } return r; } /// /// Invokes a transform function on each element of a sequence and returns the maximum value. /// /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The maximum value in the transform of the sequence. public static int Min(this Span source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); if (selector == null) throw new ArgumentNullException(nameof(selector)); int r = int.MaxValue; for (int i = 0; i < source.Length; i++) { var v = selector(source[i]); if (v < r) r = v; } return r; } /// /// Returns the minimum value in a sequence of values. /// /// A sequence of values to determine the minimum of. /// The minimum value in the sequence public static long Min(this Span source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); long r = long.MaxValue; for (int i = 0; i < source.Length; i++) { if (source[i] < r) r = source[i]; } return r; } /// /// Invokes a transform function on each element of a sequence and returns the maximum value. /// /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The maximum value in the transform of the sequence. public static long Min(this Span source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); if (selector == null) throw new ArgumentNullException(nameof(selector)); long r = long.MaxValue; for (int i = 0; i < source.Length; i++) { var v = selector(source[i]); if (v < r) r = v; } return r; } /// /// Returns the minimum value in a sequence of values. /// /// A sequence of values to determine the minimum of. /// The minimum value in the sequence public static float Min(this Span source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); float r = float.MaxValue; for (int i = 0; i < source.Length; i++) { if (source[i] < r) r = source[i]; else if (float.IsNaN(source[i])) return source[i]; } return r; } /// /// Invokes a transform function on each element of a sequence and returns the maximum value. /// /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The maximum value in the transform of the sequence. public static float Min(this Span source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); if (selector == null) throw new ArgumentNullException(nameof(selector)); float r = float.MaxValue; for (int i = 0; i < source.Length; i++) { var v = selector(source[i]); if (v < r) r = v; else if (float.IsNaN(v)) return v; } return r; } /// /// Returns the minimum value in a sequence of values. /// /// A sequence of values to determine the minimum of. /// The minimum value in the sequence public static double Min(this Span source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); double r = double.MaxValue; for (int i = 0; i < source.Length; i++) { if (source[i] < r) r = source[i]; else if (double.IsNaN(source[i])) return source[i]; } return r; } /// /// Invokes a transform function on each element of a sequence and returns the maximum value. /// /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The maximum value in the transform of the sequence. public static double Min(this Span source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); if (selector == null) throw new ArgumentNullException(nameof(selector)); double r = double.MaxValue; for (int i = 0; i < source.Length; i++) { var v = selector(source[i]); if (v < r) r = v; else if (double.IsNaN(v)) return v; } return r; } /// /// Returns the minimum value in a sequence of values. /// /// A sequence of values to determine the minimum of. /// The minimum value in the sequence public static decimal Min(this Span source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); decimal r = decimal.MaxValue; for (int i = 0; i < source.Length; i++) { if (source[i] < r) r = source[i]; } return r; } /// /// Invokes a transform function on each element of a sequence and returns the maximum value. /// /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The maximum value in the transform of the sequence. public static decimal Min(this Span source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); if (selector == null) throw new ArgumentNullException(nameof(selector)); decimal r = decimal.MaxValue; for (int i = 0; i < source.Length; i++) { var v = selector(source[i]); if (v < r) r = v; } return r; } #endif // -------------------------- LISTS -------------------------------------------- /// /// Returns the minimum value in a sequence of values. /// /// A sequence of values to determine the minimum of. /// The minimum value in the sequence public static T Min(this List source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Count == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); Comparer comparer = Comparer.Default; T r = default(T); if (r == null) { r = source[0]; for (int i = 1; i < source.Count; i++) { if (source[i] != null && comparer.Compare(source[i], r) < 0) r = source[i]; } } else { r = source[0]; for (int i = 1; i < source.Count; i++) { if (comparer.Compare(source[i], r) < 0) r = source[i]; } } return r; } /// /// Returns the minimum value in a sequence of values. /// /// A sequence of values to determine the minimum of. /// The minimum value in the sequence public static int Min(this List source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Count == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); int r = int.MaxValue; for (int i = 0; i < source.Count; i++) { if (source[i] < r) r = source[i]; } return r; } /// /// Invokes a transform function on each element of a sequence and returns the maximum value. /// /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The maximum value in the transform of the sequence. public static int Min(this List source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Count == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); if (selector == null) throw new ArgumentNullException(nameof(selector)); int r = int.MaxValue; for (int i = 0; i < source.Count; i++) { var v = selector(source[i]); if (v < r) r = v; } return r; } /// /// Returns the minimum value in a sequence of values. /// /// A sequence of values to determine the minimum of. /// The minimum value in the sequence public static long Min(this List source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Count == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); long r = long.MaxValue; for (int i = 0; i < source.Count; i++) { if (source[i] < r) r = source[i]; } return r; } /// /// Invokes a transform function on each element of a sequence and returns the maximum value. /// /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The maximum value in the transform of the sequence. public static long Min(this List source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Count == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); if (selector == null) throw new ArgumentNullException(nameof(selector)); long r = long.MaxValue; for (int i = 0; i < source.Count; i++) { var v = selector(source[i]); if (v < r) r = v; } return r; } /// /// Returns the minimum value in a sequence of values. /// /// A sequence of values to determine the minimum of. /// The minimum value in the sequence public static float Min(this List source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Count == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); float r = float.MaxValue; for (int i = 0; i < source.Count; i++) { if (source[i] < r) r = source[i]; else if (float.IsNaN(source[i])) return source[i]; } return r; } /// /// Invokes a transform function on each element of a sequence and returns the maximum value. /// /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The maximum value in the transform of the sequence. public static float Min(this List source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Count == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); if (selector == null) throw new ArgumentNullException(nameof(selector)); float r = float.MaxValue; for (int i = 0; i < source.Count; i++) { var v = selector(source[i]); if (v < r) r = v; else if (float.IsNaN(v)) return v; } return r; } /// /// Returns the minimum value in a sequence of values. /// /// A sequence of values to determine the minimum of. /// The minimum value in the sequence public static double Min(this List source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Count == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); double r = double.MaxValue; for (int i = 0; i < source.Count; i++) { if (source[i] < r) r = source[i]; else if (double.IsNaN(source[i])) return source[i]; } return r; } /// /// Invokes a transform function on each element of a sequence and returns the maximum value. /// /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The maximum value in the transform of the sequence. public static double Min(this List source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Count == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); if (selector == null) throw new ArgumentNullException(nameof(selector)); double r = double.MaxValue; for (int i = 0; i < source.Count; i++) { var v = selector(source[i]); if (v < r) r = v; else if (double.IsNaN(v)) return v; } return r; } /// /// Returns the minimum value in a sequence of values. /// /// A sequence of values to determine the minimum of. /// The minimum value in the sequence public static decimal Min(this List source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Count == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); decimal r = decimal.MaxValue; for (int i = 0; i < source.Count; i++) { if (source[i] < r) r = source[i]; } return r; } /// /// Invokes a transform function on each element of a sequence and returns the maximum value. /// /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The maximum value in the transform of the sequence. public static decimal Min(this List source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Count == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); decimal r = decimal.MaxValue; for (int i = 0; i < source.Count; i++) { var v = selector(source[i]); if (v < r) r = v; } return r; } /// /// Invokes a transform function on each element of a sequence and returns the maximum value. /// /// A sequence of values to determine the maximum value of. /// A transform function to apply to each element. /// The maximum value in the transform of the sequence. public static TResult Min(this List source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (selector == null) throw new ArgumentNullException(nameof(selector)); if (source.Count == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); Comparer comparer = Comparer.Default; TResult r = default(TResult); if (r == null) { r = selector(source[0]); for (int i = 1; i < source.Count; i++) { var v = selector(source[i]); if (v != null && comparer.Compare(v, r) < 0) r = v; } } else { r = selector(source[0]); for (int i = 1; i < source.Count; i++) { var v = selector(source[i]); if (comparer.Compare(v, r) < 0) r = v; } } return r; } } } ================================================ FILE: VirtueSky/Linq/Min.cs.meta ================================================ fileFormatVersion: 2 guid: c7ae4d8470b60b043b25b615582f6a0e MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Linq/OrderBy.cs ================================================ using System; using System.Collections.Generic; namespace VirtueSky.Linq { public static partial class L { /// /// Sorts the elements of a sequence in ascending order according to a key. /// Unlike standard Linq NOT a stable sort. /// /// A sequence of values to order. /// A function to extract a key from an element. /// A Comparer to compare keys. /// A sequence whose elements are ordered according to a key public static TSource[] OrderBy(this TSource[] source, Func keySelector, IComparer comparer = null) { if (source == null) throw new ArgumentNullException(nameof(source)); if (keySelector == null) throw new ArgumentNullException(nameof(keySelector)); if (comparer == null) { comparer = Comparer.Default; } var keys = new TKey[source.Length]; for (int i = 0; i < keys.Length; i++) { keys[i] = keySelector(source[i]); } var result = (TSource[])source.Clone(); Array.Sort(keys, result, comparer); return result; } /// /// Sorts the elements of a sequence in descending order according to a key. /// Unlike standard Linq NOT a stable sort. /// /// A sequence of values to order. /// A function to extract a key from an element. /// A Comparer to compare keys. /// A sequence whose elements are ordered according to a key public static TSource[] OrderByDescending(this TSource[] source, Func keySelector, IComparer comparer = null) { if (source == null) throw new ArgumentNullException(nameof(source)); if (keySelector == null) throw new ArgumentNullException(nameof(keySelector)); if (comparer == null) { comparer = Comparer.Default; } var keys = new TKey[source.Length]; for (int i = 0; i < keys.Length; i++) { keys[i] = keySelector(source[i]); } var result = (TSource[])source.Clone(); Array.Sort(keys, result, comparer.Reverse()); return result; } // ---------------------- Lists /// /// Sorts the elements of a sequence in ascending order according to a key. /// Unlike standard Linq NOT a stable sort. /// /// A sequence of values to order. /// A function to extract a key from an element. /// A Comparer to compare keys. /// A sequence whose elements are ordered according to a key public static List OrderBy(this List source, Func keySelector, IComparer comparer = null) { if (source == null) throw new ArgumentNullException(nameof(source)); if (keySelector == null) throw new ArgumentNullException(nameof(keySelector)); if (comparer == null) { comparer = Comparer.Default; } var result = new List(source); var lambdaComparer = new LambdaComparer(keySelector, comparer); result.Sort(lambdaComparer); return result; } /// /// Sorts the elements of a sequence in descending order according to a key. /// Unlike standard Linq NOT a stable sort. /// /// A sequence of values to order. /// A function to extract a key from an element. /// A Comparer to compare keys. /// A sequence whose elements are ordered according to a key public static List OrderByDescending(this List source, Func keySelector, IComparer comparer = null) { if (source == null) throw new ArgumentNullException(nameof(source)); if (keySelector == null) throw new ArgumentNullException(nameof(keySelector)); if (comparer == null) { comparer = Comparer.Default; } var result = new List(source); var lambdaComparer = new ReverseLambdaComparer(keySelector, comparer); result.Sort(lambdaComparer); return result; } } } ================================================ FILE: VirtueSky/Linq/OrderBy.cs.meta ================================================ fileFormatVersion: 2 guid: 4715c0497778f254dbfdae272dbf5648 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Linq/Range.cs ================================================ using System; using System.Collections.Generic; namespace VirtueSky.Linq { public static partial class L { /// /// Generates a sequence of integral numbers within a specified range. /// /// The value of the first integer in the sequence. /// The number of sequential integers to generate. /// A sequence that contains a range of sequential integral numbers. public static int[] RangeArray(int start, int count) { long max = ((long)start) + count - 1; if (count < 0 || max > int.MaxValue) throw new ArgumentOutOfRangeException(nameof(count)); int[] result = new int[count]; for (int i = 0; i < result.Length; i++) { result[i] = i + start; } return result; } /// /// Generates a sequence of integral numbers within a specified range. /// /// The value of the first integer in the sequence. /// The number of sequential integers to generate. /// A sequence that contains a range of sequential integral numbers. public static List RangeList(int start, int count) { long max = ((long)start) + count - 1; if (count < 0 || max > int.MaxValue) throw new ArgumentOutOfRangeException(nameof(count)); var result = new List(count); for (int i = 0; i < count; i++) { result.Add(i + start); } return result; } } } ================================================ FILE: VirtueSky/Linq/Range.cs.meta ================================================ fileFormatVersion: 2 guid: d1b703cfc9555784ba8c8780bb7f13f2 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Linq/Repeat.cs ================================================ using System.Collections.Generic; namespace VirtueSky.Linq { public static partial class L { // ------------------------ Arrays --------------------------- /// /// Generates a sequence that contains one repeated value. /// /// The value to be repeated. /// The number of times to repeat the value in the generated sequence. /// A sequence that contains a repeated value public static T[] RepeatArray(T element, int count) { var result = new T[count]; for (int i = 0; i < result.Length; i++) { result[i] = element; } return result; } // ------------------------ Lists --------------------------- /// /// Generates a sequence that contains one repeated value. /// /// The value to be repeated. /// The number of times to repeat the value in the generated sequence. /// A sequence that contains a repeated value public static List RepeatList(T element, int count) { var result = new List(count); for (int i = 0; i < count; i++) { result.Add(element); } return result; } } } ================================================ FILE: VirtueSky/Linq/Repeat.cs.meta ================================================ fileFormatVersion: 2 guid: 70b6f576d7a45084da893689dca2d9b0 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Linq/Reverse.cs ================================================ using System; using System.Collections.Generic; namespace VirtueSky.Linq { public static partial class L { /// /// Inverts the order of the elements in a sequence. /// /// A sequence of values to reverse. /// A sequence whose elements correspond to those of the input sequence in reverse order. public static T[] Reverse(this T[] source) { var result = new T[source.Length]; int lenLessOne = source.Length - 1; for (int i = 0; i < result.Length; i++) { result[i] = source[lenLessOne - i]; } return result; } /// /// Inverts the order of the elements in a sequence in place. /// The result will change itself /// /// A sequence of values to reverse. public static void ReverseOrigin(this T[] source) { Array.Reverse(source); } #if UNITY_2021_3_OR_NEWER /// /// Inverts the order of the elements in a sequence. /// /// A sequence of values to reverse. /// A sequence whose elements correspond to those of the input sequence in reverse order. public static T[] Reverse(this Span source) { var result = new T[source.Length]; int lenLessOne = source.Length - 1; for (int i = 0; i < result.Length; i++) { result[i] = source[lenLessOne - i]; } return result; } /// /// Inverts the order of the elements in a sequence in place. /// The result will change itself /// /// A sequence of values to reverse. public static void ReverseOrigin(this Span source) { MemoryExtensions.Reverse(source); } #endif /// /// Inverts the order of the elements in a sequence. /// /// A sequence of values to reverse. /// A sequence whose elements correspond to those of the input sequence in reverse order. public static List Reverse(this List source) { var result = new List(source.Count); for (int i = source.Count - 1; i >= 0; i--) { result.Add(source[i]); } return result; } /// /// Inverts the order of the elements in a sequence in place. /// The result will change itself /// /// A sequence of values to reverse. public static void ReverseOrigin(this List source) { source.Reverse(); } } } ================================================ FILE: VirtueSky/Linq/Reverse.cs.meta ================================================ fileFormatVersion: 2 guid: 56aebe035b0b1994e9b763d9e3870335 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Linq/Select.cs ================================================ using System; using System.Collections.Generic; namespace VirtueSky.Linq { public static partial class L { // -------------------------- ARRAYS -------------------------------------------- /// /// Projects each element of a sequence into a new form in place. /// The result will change itself /// /// A sequence of values to invoke a transform function on (map). /// A transform function to apply (map) to each element. public static void MapOrigin(this T[] source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (selector == null) throw new ArgumentNullException(nameof(selector)); for (int i = 0; i < source.Length; i++) { source[i] = selector(source[i]); } } /// /// Projects each element of a sequence into a new form, in place, by incorporating the element's index. /// The result will change itself /// /// A sequence of values to invoke a transform function on. /// A transform function to apply to each source element; the second parameter of the function represents the index of the source element. public static void MapOrigin(this T[] source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (selector == null) throw new ArgumentNullException(nameof(selector)); for (int i = 0; i < source.Length; i++) { source[i] = selector(source[i], i); } } /// /// Projects each element of a sequence into a new form. (map in every other language) /// /// A sequence of values to invoke a transform function on (map). /// A transform function to apply (map) to each element. /// A sequence whose elements are the result of invoking the transform function on each element (mapping) of source. public static TResult[] Map(this T[] source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (selector == null) throw new ArgumentNullException(nameof(selector)); var r = new TResult[source.Length]; for (int i = 0; i < source.Length; i++) { r[i] = selector(source[i]); } return r; } /// /// Projects each element of a sequence into a new form by incorporating the element's index. /// /// A sequence of values to invoke a transform function on. /// A transform function to apply to each source element; the second parameter of the function represents the index of the source element. /// A sequence whose elements are the result of invoking the transform function on each element of source. public static TResult[] Map(this T[] source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (selector == null) throw new ArgumentNullException(nameof(selector)); var r = new TResult[source.Length]; for (int i = 0; i < source.Length; i++) { r[i] = selector(source[i], i); } return r; } // -------------------------- this SpanS -------------------------------------------- #if UNITY_2021_3_OR_NEWER /// /// Projects each element of a sequence into a new form in place. /// The result will change itself /// /// A sequence of values to invoke a transform function on (map). /// A transform function to apply (map) to each element. public static void MapOrigin(this Span source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (selector == null) throw new ArgumentNullException(nameof(selector)); for (int i = 0; i < source.Length; i++) { source[i] = selector(source[i]); } } /// /// Projects each element of a sequence into a new form, in place, by incorporating the element's index. /// The result will change itself /// /// A sequence of values to invoke a transform function on. /// A transform function to apply to each source element; the second parameter of the function represents the index of the source element. public static void MapOrigin(this Span source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (selector == null) throw new ArgumentNullException(nameof(selector)); for (int i = 0; i < source.Length; i++) { source[i] = selector(source[i], i); } } /// /// Projects each element of a sequence into a new form. (map in every other language) /// /// A sequence of values to invoke a transform function on (map). /// A transform function to apply (map) to each element. /// A sequence whose elements are the result of invoking the transform function on each element (mapping) of source. public static TResult[] Map(this Span source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (selector == null) throw new ArgumentNullException(nameof(selector)); var r = new TResult[source.Length]; for (int i = 0; i < source.Length; i++) { r[i] = selector(source[i]); } return r; } /// /// Projects each element of a sequence into a new form by incorporating the element's index. /// /// A sequence of values to invoke a transform function on. /// A transform function to apply to each source element; the second parameter of the function represents the index of the source element. /// A sequence whose elements are the result of invoking the transform function on each element of source. public static TResult[] Map(this Span source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (selector == null) throw new ArgumentNullException(nameof(selector)); var r = new TResult[source.Length]; for (int i = 0; i < source.Length; i++) { r[i] = selector(source[i], i); } return r; } #endif // -------------------------- LISTS -------------------------------------------- /// /// Projects each element of a sequence into a new form in place. /// The result will change itself /// /// A sequence of values to invoke a transform function on (map). /// A transform function to apply (map) to each element. public static void MapOrigin(this List source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (selector == null) throw new ArgumentNullException(nameof(selector)); for (int i = 0; i < source.Count; i++) { source[i] = selector(source[i]); } } /// /// Projects each element of a sequence into a new form, in place, by incorporating the element's index. /// The result will change itself /// /// A sequence of values to invoke a transform function on. /// A transform function to apply to each source element; the second parameter of the function represents the index of the source element. public static void MapOrigin(this List source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (selector == null) throw new ArgumentNullException(nameof(selector)); for (int i = 0; i < source.Count; i++) { source[i] = selector(source[i], i); } } /// /// Projects each element of a sequence into a new form. (map in every other language) /// /// A sequence of values to invoke a transform function on (map). /// A transform function to apply (map) to each element. /// A sequence whose elements are the result of invoking the transform function on each element (mapping) of source. public static List Map(this List source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (selector == null) throw new ArgumentNullException(nameof(selector)); var r = new List(source.Count); for (int i = 0; i < source.Count; i++) { r.Add(selector(source[i])); } return r; } /// /// Projects each element of a sequence into a new form by incorporating the element's index. /// /// A sequence of values to invoke a transform function on. /// A transform function to apply to each source element; the second parameter of the function represents the index of the source element. /// A sequence whose elements are the result of invoking the transform function on each element of source. public static List Map(this List source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (selector == null) throw new ArgumentNullException(nameof(selector)); var r = new List(source.Count); for (int i = 0; i < source.Count; i++) { r.Add(selector(source[i], i)); } return r; } } } ================================================ FILE: VirtueSky/Linq/Select.cs.meta ================================================ fileFormatVersion: 2 guid: 05242163f530f56499e08659945839c6 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Linq/SelectMany.cs ================================================ using System; using System.Collections.Generic; namespace VirtueSky.Linq { public static partial class L { // -------------------------- Arrays -------------------------------------------- /// /// Projects each element of a sequence to another sequence and flattens the resulting sequences into one sequence. /// Yo dawg, I heard you like sequences. /// /// A sequence of values to project. /// A transform function to apply to each element. /// A sequence whose elements are the result of invoking the one-to-many transform function on each element of the input sequence. public static TResult[] SelectMany(this TSource[] source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (selector == null) throw new ArgumentNullException(nameof(selector)); var result = new List(source.Length); for (int i = 0; i < source.Length; i++) { var va = selector(source[i]); for (int j = 0; j < va.Length; j++) { result.Add(va[j]); } } return result.ToArray(); } /// /// Projects each element of a sequence to another sequence and flattens the resulting sequences into one sequence /// utilizing the index of each element. /// /// A sequence of values to project. /// A transform function to apply to each element and it's index. /// A sequence whose elements are the result of invoking the one-to-many transform function on each element and index of the input sequence. public static TResult[] SelectMany(this TSource[] source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (selector == null) throw new ArgumentNullException(nameof(selector)); var result = new List(source.Length); for (int i = 0; i < source.Length; i++) { var va = selector(source[i], i); for (int j = 0; j < va.Length; j++) { result.Add(va[j]); } } return result.ToArray(); } // -------------------------- this Spans -------------------------------------------- #if UNITY_2021_3_OR_NEWER /// /// Projects each element of a sequence to another sequence and flattens the resulting sequences into one sequence. /// Yo dawg, I heard you like sequences. /// /// A sequence of values to project. /// A transform function to apply to each element. /// A sequence whose elements are the result of invoking the one-to-many transform function on each element of the input sequence. public static TResult[] SelectMany(this Span source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (selector == null) throw new ArgumentNullException(nameof(selector)); var result = new List(source.Length); for (int i = 0; i < source.Length; i++) { var va = selector(source[i]); for (int j = 0; j < va.Length; j++) { result.Add(va[j]); } } return result.ToArray(); } /// /// Projects each element of a sequence to another sequence and flattens the resulting sequences into one sequence /// utilizing the index of each element. /// /// A sequence of values to project. /// A transform function to apply to each element and it's index. /// A sequence whose elements are the result of invoking the one-to-many transform function on each element and index of the input sequence. public static TResult[] SelectMany(this Span source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (selector == null) throw new ArgumentNullException(nameof(selector)); var result = new List(source.Length); for (int i = 0; i < source.Length; i++) { var va = selector(source[i], i); for (int j = 0; j < va.Length; j++) { result.Add(va[j]); } } return result.ToArray(); } #endif // -------------------------- LISTS -------------------------------------------- /// /// Projects each element of a sequence to another sequence and flattens the resulting sequences into one sequence. /// Yo dawg, I heard you like sequences. /// /// A sequence of values to project. /// A transform function to apply to each element. /// A sequence whose elements are the result of invoking the one-to-many transform function on each element of the input sequence. public static List SelectMany(this List source, Func> selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (selector == null) throw new ArgumentNullException(nameof(selector)); var result = new List(source.Count); for (int i = 0; i < source.Count; i++) { var va = selector(source[i]); for (int j = 0; j < va.Count; j++) { result.Add(va[j]); } } return result; } /// /// Projects each element of a sequence to another sequence and flattens the resulting sequences into one sequence /// utilizing the index of each element. /// /// A sequence of values to project. /// A transform function to apply to each element and it's index. /// A sequence whose elements are the result of invoking the one-to-many transform function on each element and index of the input sequence. public static List SelectMany(this List source, Func> selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (selector == null) throw new ArgumentNullException(nameof(selector)); var result = new List(source.Count); for (int i = 0; i < source.Count; i++) { var va = selector(source[i], i); for (int j = 0; j < va.Count; j++) { result.Add(va[j]); } } return result; } } } ================================================ FILE: VirtueSky/Linq/SelectMany.cs.meta ================================================ fileFormatVersion: 2 guid: be9b005d1735e8b4e9c87398cfacf2c2 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Linq/SelectWhere.cs ================================================ using System; using System.Collections.Generic; namespace VirtueSky.Linq { public static partial class L { // -------------------------- ARRAYS -------------------------------------------- /// /// Combines Select and Where into a single call for optimal /// performance. /// /// The input sequence to filter and select /// The transformation to apply before filtering. /// The predicate with which to filter result. /// A sequence transformed and then filtered by selector and predicate. public static TResult[] MapFilter(this T[] source, Func selector, Func predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); var result = new TResult[source.Length]; int idx = 0; for (int i = 0; i < source.Length; i++) { var s = selector(source[i]); if (predicate(s)) { result[idx] = s; idx++; } } Array.Resize(ref result, idx); return result; } /// /// Combines Select and Where with indexes into a single call for optimal /// performance. /// /// The input sequence to filter and select /// The transformation with index to apply before filtering. /// The predicate with index with which to filter result. /// A sequence transformed and then filtered by selector and predicate with indexes. public static TResult[] MapFilter(this T[] source, Func selector, Func predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); var result = new TResult[source.Length]; int idx = 0; for (int i = 0; i < source.Length; i++) { var s = selector(source[i], i); if (predicate(s, i)) { result[idx] = s; idx++; } } Array.Resize(ref result, idx); return result; } // -------------------------- this Spans -------------------------------------------- #if UNITY_2021_3_OR_NEWER /// /// Combines Select and Where into a single call for optimal /// performance. /// /// The input sequence to filter and select /// The transformation to apply before filtering. /// The predicate with which to filter result. /// A sequence transformed and then filtered by selector and predicate. public static TResult[] MapFilter(this Span source, Func selector, Func predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); var result = new TResult[source.Length]; int idx = 0; for (int i = 0; i < source.Length; i++) { var s = selector(source[i]); if (predicate(s)) { result[idx] = s; idx++; } } Array.Resize(ref result, idx); return result; } /// /// Combines Select and Where with indexes into a single call for optimal /// performance. /// /// The input sequence to filter and select /// The transformation with index to apply before filtering. /// The predicate with index with which to filter result. /// A sequence transformed and then filtered by selector and predicate with indexes. public static TResult[] MapFilter(this Span source, Func selector, Func predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); var result = new TResult[source.Length]; int idx = 0; for (int i = 0; i < source.Length; i++) { var s = selector(source[i], i); if (predicate(s, i)) { result[idx] = s; idx++; } } Array.Resize(ref result, idx); return result; } #endif // -------------------------- LISTS -------------------------------------------- /// /// Combines Select and Where into a single call for optimal /// performance. /// /// The input sequence to filter and select /// The transformation to apply before filtering. /// The predicate with which to filter result. /// A sequence transformed and then filtered by selector and predicate. public static List MapFilter(this List source, Func selector, Func predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); var r = new List(); for (int i = 0; i < source.Count; i++) { var s = selector(source[i]); if (predicate(s)) r.Add(s); } return r; } /// /// Combines Select and Where with indexes into a single call for optimal /// performance. /// /// The input sequence to filter and select /// The transformation with index to apply before filtering. /// The predicate with index with which to filter result. /// A sequence transformed and then filtered by selector and predicate with indexes. public static List MapFilter(this List source, Func selector, Func predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); var r = new List(); for (int i = 0; i < source.Count; i++) { var s = selector(source[i], i); if (predicate(s, i)) r.Add(s); } return r; } } } ================================================ FILE: VirtueSky/Linq/SelectWhere.cs.meta ================================================ fileFormatVersion: 2 guid: 9723c36dde8b1fb44baf0a42e21c0e1d MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Linq/SequenceEqual.cs ================================================ using System.Collections.Generic; using System; namespace VirtueSky.Linq { public static partial class L { /// /// Determines whether two sequences are equal by comparing the elements by using the /// provided comparer or the default equality comparer for their type if none is provided. /// /// A sequence to compare to second. /// A sequence to compare to first. /// An optional Comparer to use for the comparison. /// true of the two sources are of equal length and their corresponding /// elements are equal according to the equality comparer. Otherwise, false. public static bool SequenceEqual(this T[] first, T[] second, IEqualityComparer comparer = null) { if (comparer == null) { comparer = EqualityComparer.Default; } if (first == null) throw new ArgumentNullException(nameof(first)); if (second == null) throw new ArgumentNullException(nameof(second)); if (first.Length != second.Length) return false; if (first == second) return true; for (int i = 0; i < first.Length; i++) { if (!comparer.Equals(first[i], second[i])) return false; } return true; } /// /// Determines whether two sequences are equal by comparing the elements by using the /// provided comparer or the default equality comparer for their type if none is provided. /// /// A sequence to compare to second. /// A sequence to compare to first. /// An optional Comparer to use for the comparison. /// An array of integers, where the value corresponds to IComparer.Compare indicating less than, greater than, or equals public static int[] SequenceCompare(this T[] first, T[] second, IComparer comparer = null) { if (first == null) throw new ArgumentNullException(nameof(first)); if (second == null) throw new ArgumentNullException(nameof(second)); if (comparer == null) { comparer = Comparer.Default; } if (first.Length != second.Length) throw new NotSupportedException(); var result = new int[first.Length]; for (int i = 0; i < first.Length; i++) { result[i] = comparer.Compare(first[i], second[i]); } return result; } /// /// Determines whether two sequences are equal by comparing the elements by using the /// provided comparer or the default equality comparer for their type if none is provided. /// /// A sequence to compare to second. /// A sequence to compare to first. /// An optional Comparer to use for the comparison. /// true of the two sources are of equal length and their corresponding /// elements are equal according to the equality comparer. Otherwise, false. public static bool SequenceEqual(this T[] first, List second, IEqualityComparer comparer = null) { if (comparer == null) { comparer = EqualityComparer.Default; } if (first == null) throw new ArgumentNullException(nameof(first)); if (second == null) throw new ArgumentNullException(nameof(second)); if (first.Length != second.Count) return false; for (int i = 0; i < first.Length; i++) { if (!comparer.Equals(first[i], second[i])) return false; } return true; } /// /// Determines whether two sequences are equal by comparing the elements by using the /// provided comparer or the default equality comparer for their type if none is provided. /// /// A sequence to compare to second. /// A sequence to compare to first. /// An optional Comparer to use for the comparison. /// true of the two sources are of equal length and their corresponding /// elements are equal according to the equality comparer. Otherwise, false. public static bool SequenceEqual(this List first, T[] second, IEqualityComparer comparer = null) { if (comparer == null) { comparer = EqualityComparer.Default; } if (first == null) throw new ArgumentNullException(nameof(first)); if (second == null) throw new ArgumentNullException(nameof(second)); if (first.Count != second.Length) return false; for (int i = 0; i < first.Count; i++) { if (!comparer.Equals(first[i], second[i])) return false; } return true; } /*---- Spans ----*/ #if UNITY_2021_3_OR_NEWER /// /// Determines whether two sequences are equal by comparing the elements by using the /// provided comparer or the default equality comparer for their type if none is provided. /// /// A sequence to compare to second. /// A sequence to compare to first. /// An optional Comparer to use for the comparison. /// true of the two sources are of equal length and their corresponding /// elements are equal according to the equality comparer. Otherwise, false. public static bool SequenceEqual(this Span first, Span second, IEqualityComparer comparer = null) { if (comparer == null) { comparer = EqualityComparer.Default; } if (first == null) throw new ArgumentNullException(nameof(first)); if (second == null) throw new ArgumentNullException(nameof(second)); if (first.Length != second.Length) return false; if (first == second) return true; for (int i = 0; i < first.Length; i++) { if (!comparer.Equals(first[i], second[i])) return false; } return true; } /// /// Determines whether two sequences are equal by comparing the elements by using the /// provided comparer or the default equality comparer for their type if none is provided. /// /// A sequence to compare to second. /// A sequence to compare to first. /// An optional Comparer to use for the comparison. /// true of the two sources are of equal length and their corresponding /// elements are equal according to the equality comparer. Otherwise, false. public static bool SequenceEqual(this Span first, List second, IEqualityComparer comparer = null) { if (comparer == null) { comparer = EqualityComparer.Default; } if (first == null) throw new ArgumentNullException(nameof(first)); if (second == null) throw new ArgumentNullException(nameof(second)); if (first.Length != second.Count) return false; for (int i = 0; i < first.Length; i++) { if (!comparer.Equals(first[i], second[i])) return false; } return true; } /// /// Determines whether two sequences are equal by comparing the elements by using the /// provided comparer or the default equality comparer for their type if none is provided. /// /// A sequence to compare to second. /// A sequence to compare to first. /// An optional Comparer to use for the comparison. /// true of the two sources are of equal length and their corresponding /// elements are equal according to the equality comparer. Otherwise, false. public static bool SequenceEqual(this List first, Span second, IEqualityComparer comparer = null) { if (comparer == null) { comparer = EqualityComparer.Default; } if (first == null) throw new ArgumentNullException(nameof(first)); if (second == null) throw new ArgumentNullException(nameof(second)); if (first.Count != second.Length) return false; for (int i = 0; i < first.Count; i++) { if (!comparer.Equals(first[i], second[i])) return false; } return true; } #endif /* ------------ List ---------------- */ /// /// Determines whether two sequences are equal by comparing the elements by using the /// provided comparer or the default equality comparer for their type if none is provided. /// /// A sequence to compare to second. /// A sequence to compare to first. /// An optional Comparer to use for the comparison. /// true of the two sources are of equal length and their corresponding /// elements are equal according to the equality comparer. Otherwise, false. public static bool SequenceEqual(this List first, List second, IEqualityComparer comparer = null) { if (comparer == null) { comparer = EqualityComparer.Default; } if (first == null) throw new ArgumentNullException(nameof(first)); if (second == null) throw new ArgumentNullException(nameof(second)); if (first.Count != second.Count) return false; if (first == second) return true; for (int i = 0; i < first.Count; i++) { if (!comparer.Equals(first[i], second[i])) return false; } return true; } } } ================================================ FILE: VirtueSky/Linq/SequenceEqual.cs.meta ================================================ fileFormatVersion: 2 guid: b325f40656270884781d1acfe34ec446 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Linq/Single.cs ================================================ using System; using System.Collections.Generic; namespace VirtueSky.Linq { public static partial class L { // --------------------------- Arrays ---------------------------- /// /// Returns the only element of a sequence, and throws an exception if there is not exactly one element in the sequence. /// /// A sequence to return the single element of /// The single element of the input sequence or default if no elements exist. public static T Single(this T[] source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); if (source.Length > 1) throw new InvalidOperationException("Source sequence contains more than one element."); return source[0]; } /// /// 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. /// /// A sequence to return the single element of /// The single element of the input sequence public static T SingleOrDefault(this T[] source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) return default(T); if (source.Length > 1) throw new InvalidOperationException("Source sequence contains more than one element."); return source[0]; } /// /// Returns the only element of a sequence that satisfies a specified condition, and throws an exception if more than one such element exists. /// /// A sequence to return a single element from. /// A function to test an element for a condition. /// The single element of the input sequence that satisfies a condition. public static T Single(this T[] source, Func predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); T result = default(T); bool foundMatch = false; for (int i = 0; i < source.Length; i++) { if (predicate(source[i])) { if (foundMatch) throw new InvalidOperationException("Sequence contains more than one matching element"); result = source[i]; foundMatch = true; } } if (foundMatch) return result; throw new InvalidOperationException("Sequence contains no matching element"); } /// /// Returns the only element of a sequence that satisfies a specified condition, or a default value if /// no such element exists, and throws an exception if more than one such element exists. /// /// A sequence to return a single element from. /// A function to test an element for a condition. /// The single element of the input sequence that satisfies a condition or default value if no such element is found. public static T SingleOrDefault(this T[] source, Func predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); T result = default(T); bool foundMatch = false; for (int i = 0; i < source.Length; i++) { if (predicate(source[i])) { if (foundMatch) throw new InvalidOperationException("Sequence contains more than one matching element"); result = source[i]; foundMatch = true; } } return result; } // --------------------------- Spans ---------------------------- #if UNITY_2021_3_OR_NEWER /// /// Returns the only element of a sequence, and throws an exception if there is not exactly one element in the sequence. /// /// A sequence to return the single element of /// The single element of the input sequence or default if no elements exist. public static T Single(this Span source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); if (source.Length > 1) throw new InvalidOperationException("Source sequence contains more than one element."); return source[0]; } /// /// 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. /// /// A sequence to return the single element of /// The single element of the input sequence public static T SingleOrDefault(this Span source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Length == 0) return default(T); if (source.Length > 1) throw new InvalidOperationException("Source sequence contains more than one element."); return source[0]; } /// /// Returns the only element of a sequence that satisfies a specified condition, and throws an exception if more than one such element exists. /// /// A sequence to return a single element from. /// A function to test an element for a condition. /// The single element of the input sequence that satisfies a condition. public static T Single(this Span source, Func predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); T result = default(T); bool foundMatch = false; for (int i = 0; i < source.Length; i++) { if (predicate(source[i])) { if (foundMatch) throw new InvalidOperationException("Sequence contains more than one matching element"); result = source[i]; foundMatch = true; } } if (foundMatch) return result; throw new InvalidOperationException("Sequence contains no matching element"); } /// /// Returns the only element of a sequence that satisfies a specified condition, or a default value if /// no such element exists, and throws an exception if more than one such element exists. /// /// A sequence to return a single element from. /// A function to test an element for a condition. /// The single element of the input sequence that satisfies a condition or default value if no such element is found. public static T SingleOrDefault(this Span source, Func predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); T result = default(T); bool foundMatch = false; for (int i = 0; i < source.Length; i++) { if (predicate(source[i])) { if (foundMatch) throw new InvalidOperationException("Sequence contains more than one matching element"); result = source[i]; foundMatch = true; } } return result; } #endif // --------------------------- Lists ---------------------------- /// /// Returns the only element of a sequence, and throws an exception if there is not exactly one element in the sequence. /// /// A sequence to return the single element of /// The single element of the input sequence public static T Single(this List source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Count == 0) throw new InvalidOperationException("Source sequence doesn't contain any elements."); if (source.Count > 1) throw new InvalidOperationException("Source sequence contains more than one element."); return source[0]; } /// /// 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. /// /// A sequence to return the single element of /// The single element of the input sequence or default if no elements exist. public static T SingleOrDefault(this List source) { if (source == null) throw new ArgumentNullException(nameof(source)); if (source.Count == 0) return default(T); if (source.Count > 1) throw new InvalidOperationException("Source sequence contains more than one element."); return source[0]; } /// /// Returns the only element of a sequence that satisfies a specified condition, and throws an exception if more than one such element exists. /// /// A sequence to return a single element from. /// A function to test an element for a condition. /// The single element of the input sequence that satisfies a condition. public static T Single(this List source, Func predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); T result = default(T); bool foundMatch = false; for (int i = 0; i < source.Count; i++) { if (predicate(source[i])) { if (foundMatch) throw new InvalidOperationException("Sequence contains more than one matching element"); result = source[i]; foundMatch = true; } } if (foundMatch) return result; throw new InvalidOperationException("Sequence contains no matching element"); } /// /// Returns the only element of a sequence that satisfies a specified condition, or a default value if /// no such element exists, and throws an exception if more than one such element exists. /// /// A sequence to return a single element from. /// A function to test an element for a condition. /// The single element of the input sequence that satisfies a condition or default value if no such element is found. public static T SingleOrDefault(this List source, Func predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); T result = default(T); bool foundMatch = false; for (int i = 0; i < source.Count; i++) { if (predicate(source[i])) { if (foundMatch) throw new InvalidOperationException("Sequence contains more than one matching element"); result = source[i]; foundMatch = true; } } return result; } } } ================================================ FILE: VirtueSky/Linq/Single.cs.meta ================================================ fileFormatVersion: 2 guid: d320db55c90ee5e409eda1e9b4086486 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Linq/Skip.cs ================================================ using System; using System.Collections.Generic; namespace VirtueSky.Linq { public static partial class L { /// /// Bypasses a specified number of elements in a sequence and then returns the remaining elements. /// /// A sequence to return elements from. /// The number of elements to skip before returning the remaining elements. /// A sequence that contains the elements that occur after the specified index in the input sequence. public static T[] Skip(this T[] source, int count) { if (source == null) throw new ArgumentNullException(nameof(source)); if (count < 0) { count = 0; } else if (count > source.Length) { return new T[0]; } var result = new T[source.Length - count]; Array.Copy(source, count, result, 0, result.Length); return result; } /// /// Bypasses elements in a sequence as long as a specified condition is true and then returns the remaining elements. /// /// A sequence to return elements from. /// A function to test each element for a condition. /// 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. public static T[] SkipWhile(this T[] source, Func predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); int i = 0; for (; i < source.Length; i++) { if (!predicate(source[i])) break; } var result = new T[source.Length - i]; Array.Copy(source, i, result, 0, result.Length); return result; } /*------------- SPans ---------------- */ #if UNITY_2021_3_OR_NEWER /// /// Bypasses a specified number of elements in a sequence and then returns the remaining elements. /// /// A sequence to return elements from. /// The number of elements to skip before returning the remaining elements. /// A sequence that contains the elements that occur after the specified index in the input sequence. public static T[] Skip(this Span source, int count) { if (source == null) throw new ArgumentNullException(nameof(source)); if (count < 0) { count = 0; } else if (count > source.Length) { return new T[0]; } var result = new T[source.Length - count]; for (int i = count; i < source.Length; i++) { result[i - count] = source[i]; } return result; } /// /// Bypasses elements in a sequence as long as a specified condition is true and then returns the remaining elements. /// /// A sequence to return elements from. /// A function to test each element for a condition. /// 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. public static T[] SkipWhile(this Span source, Func predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); int count = 0; for (; count < source.Length; count++) { if (!predicate(source[count])) break; } var result = new T[source.Length - count]; for (int i = count; i < source.Length; i++) { result[i - count] = source[i]; } return result; } #endif // ------------- Lists ---------------- /// /// Bypasses a specified number of elements in a sequence and then returns the remaining elements. /// /// A sequence to return elements from. /// The number of elements to skip before returning the remaining elements. /// A sequence that contains the elements that occur after the specified index in the input sequence. public static List Skip(this List source, int count) { if (source == null) throw new ArgumentNullException(nameof(source)); if (count < 0) { count = 0; } else if (count > source.Count) { return new List(); } var result = new List(source.Count - count); for (int i = count; i < source.Count; i++) { result.Add(source[i]); } return result; } /// /// Bypasses elements in a sequence as long as a specified condition is true and then returns the remaining elements. /// /// A sequence to return elements from. /// A function to test each element for a condition. /// 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. public static List SkipWhile(this List source, Func predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); int i = 0; for (; i < source.Count; i++) { if (!predicate(source[i])) { break; } } var result = new List(source.Count - i); for (; i < source.Count; i++) { result.Add(source[i]); } return result; } } } ================================================ FILE: VirtueSky/Linq/Skip.cs.meta ================================================ fileFormatVersion: 2 guid: 9eac67b4bf84bcb4bba4ac6b9eeb25f4 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Linq/Sum.cs ================================================ using System; using System.Collections.Generic; namespace VirtueSky.Linq { public static partial class L { // -------------------------- ARRAYS -------------------------------------------- /// /// Adds a sequence of values. /// /// The sequence to add. /// The sum of the sequence. public static int Sum(this int[] source) { if (source == null) throw new ArgumentNullException(nameof(source)); int sum = 0; checked { foreach (var v in source) { sum += v; } } return sum; } /// /// Adds the transformed sequence of elements. /// /// The sequence of values to transform then sum. /// A transformation function. /// The sum of the transformed elements. public static int Sum(this T[] source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (selector == null) throw new ArgumentNullException(nameof(selector)); int sum = 0; checked { foreach (var v in source) { sum += selector(v); } } return sum; } /// /// Adds a sequence of values. /// /// The sequence to add. /// The sum of the sequence. public static long Sum(this long[] source) { if (source == null) throw new ArgumentNullException(nameof(source)); long sum = 0; checked { foreach (var v in source) { sum += v; } } return sum; } /// /// Adds the transformed sequence of elements. /// /// The sequence of values to transform then sum. /// A transformation function. /// The sum of the transformed elements. public static long Sum(this T[] source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (selector == null) throw new ArgumentNullException(nameof(selector)); long sum = 0; checked { foreach (var v in source) { sum += selector(v); } } return sum; } /// /// Adds a sequence of values. /// /// The sequence to add. /// The sum of the sequence. public static float Sum(this float[] source) { if (source == null) throw new ArgumentNullException(nameof(source)); double sum = 0; foreach (var v in source) { sum += v; } return (float)sum; } /// /// Adds the transformed sequence of elements. /// /// The sequence of values to transform then sum. /// A transformation function. /// The sum of the transformed elements. public static float Sum(this T[] source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (selector == null) throw new ArgumentNullException(nameof(selector)); double sum = 0; foreach (var v in source) { sum += selector(v); } return (float)sum; } /// /// Adds a sequence of values. /// /// The sequence to add. /// The sum of the sequence. public static double Sum(this double[] source) { if (source == null) throw new ArgumentNullException(nameof(source)); double sum = 0; foreach (var v in source) { sum += v; } return sum; } /// /// Adds the transformed sequence of elements. /// /// The sequence of values to transform then sum. /// A transformation function. /// The sum of the transformed elements. public static double Sum(this T[] source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (selector == null) throw new ArgumentNullException(nameof(selector)); double sum = 0; foreach (var v in source) { sum += selector(v); } return sum; } /// /// Adds a sequence of values. /// /// The sequence to add. /// The sum of the sequence. public static decimal Sum(this decimal[] source) { if (source == null) throw new ArgumentNullException(nameof(source)); decimal sum = 0; foreach (var v in source) { sum += v; } return sum; } /// /// Adds the transformed sequence of elements. /// /// The sequence of values to transform then sum. /// A transformation function. /// The sum of the transformed elements. public static decimal Sum(this T[] source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (selector == null) throw new ArgumentNullException(nameof(selector)); decimal sum = 0; foreach (var v in source) { sum += selector(v); } return sum; } /*---- Spans ---*/ #if UNITY_2021_3_OR_NEWER /// /// Adds a sequence of values. /// /// The sequence to add. /// The sum of the sequence. public static int Sum(this Span source) { if (source == null) throw new ArgumentNullException(nameof(source)); int sum = 0; checked { foreach (var v in source) { sum += v; } } return sum; } /// /// Adds the transformed sequence of elements. /// /// The sequence of values to transform then sum. /// A transformation function. /// The sum of the transformed elements. public static int Sum(this Span source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (selector == null) throw new ArgumentNullException(nameof(selector)); int sum = 0; checked { foreach (var v in source) { sum += selector(v); } } return sum; } /// /// Adds a sequence of values. /// /// The sequence to add. /// The sum of the sequence. public static long Sum(this Span source) { if (source == null) throw new ArgumentNullException(nameof(source)); long sum = 0; checked { foreach (var v in source) { sum += v; } } return sum; } /// /// Adds the transformed sequence of elements. /// /// The sequence of values to transform then sum. /// A transformation function. /// The sum of the transformed elements. public static long Sum(this Span source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (selector == null) throw new ArgumentNullException(nameof(selector)); long sum = 0; checked { foreach (var v in source) { sum += selector(v); } } return sum; } /// /// Adds a sequence of values. /// /// The sequence to add. /// The sum of the sequence. public static float Sum(this Span source) { if (source == null) throw new ArgumentNullException(nameof(source)); double sum = 0; foreach (var v in source) { sum += v; } return (float)sum; } /// /// Adds the transformed sequence of elements. /// /// The sequence of values to transform then sum. /// A transformation function. /// The sum of the transformed elements. public static float Sum(this Span source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (selector == null) throw new ArgumentNullException(nameof(selector)); double sum = 0; foreach (var v in source) { sum += selector(v); } return (float)sum; } /// /// Adds a sequence of values. /// /// The sequence to add. /// The sum of the sequence. public static double Sum(this Span source) { if (source == null) throw new ArgumentNullException(nameof(source)); double sum = 0; foreach (var v in source) { sum += v; } return sum; } /// /// Adds the transformed sequence of elements. /// /// The sequence of values to transform then sum. /// A transformation function. /// The sum of the transformed elements. public static double Sum(this Span source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (selector == null) throw new ArgumentNullException(nameof(selector)); double sum = 0; foreach (var v in source) { sum += selector(v); } return sum; } /// /// Adds a sequence of values. /// /// The sequence to add. /// The sum of the sequence. public static decimal Sum(this Span source) { if (source == null) throw new ArgumentNullException(nameof(source)); decimal sum = 0; foreach (var v in source) { sum += v; } return sum; } /// /// Adds the transformed sequence of elements. /// /// The sequence of values to transform then sum. /// A transformation function. /// The sum of the transformed elements. public static decimal Sum(this Span source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (selector == null) throw new ArgumentNullException(nameof(selector)); decimal sum = 0; foreach (var v in source) { sum += selector(v); } return sum; } #endif // -------------------------- LISTS -------------------------------------------- /// /// Adds a sequence of values. /// /// The sequence to add. /// The sum of the sequence. public static int Sum(this List source) { if (source == null) throw new ArgumentNullException(nameof(source)); int sum = 0; checked { for (int i = 0; i < source.Count; i++) { sum += source[i]; } } return sum; } /// /// Adds the transformed sequence of elements. /// /// The sequence of values to transform then sum. /// A transformation function. /// The sum of the transformed elements. public static int Sum(this List source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (selector == null) throw new ArgumentNullException(nameof(selector)); int sum = 0; checked { for (int i = 0; i < source.Count; i++) { sum += selector(source[i]); } } return sum; } /// /// Adds a sequence of values. /// /// The sequence to add. /// The sum of the sequence. public static long Sum(this List source) { if (source == null) throw new ArgumentNullException(nameof(source)); long sum = 0; checked { for (int i = 0; i < source.Count; i++) { sum += source[i]; } } return sum; } /// /// Adds the transformed sequence of elements. /// /// The sequence of values to transform then sum. /// A transformation function. /// The sum of the transformed elements. public static long Sum(this List source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (selector == null) throw new ArgumentNullException(nameof(selector)); long sum = 0; checked { for (int i = 0; i < source.Count; i++) { sum += selector(source[i]); } } return sum; } /// /// Adds a sequence of values. /// /// The sequence to add. /// The sum of the sequence. public static float Sum(this List source) { if (source == null) throw new ArgumentNullException(nameof(source)); double sum = 0; for (int i = 0; i < source.Count; i++) { sum += source[i]; } return (float)sum; } /// /// Adds the transformed sequence of elements. /// /// The sequence of values to transform then sum. /// A transformation function. /// The sum of the transformed elements. public static float Sum(this List source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (selector == null) throw new ArgumentNullException(nameof(selector)); double sum = 0; for (int i = 0; i < source.Count; i++) { sum += selector(source[i]); } return (float)sum; } /// /// Adds a sequence of values. /// /// The sequence to add. /// The sum of the sequence. public static double Sum(this List source) { if (source == null) throw new ArgumentNullException(nameof(source)); double sum = 0; for (int i = 0; i < source.Count; i++) { sum += source[i]; } return sum; } /// /// Adds the transformed sequence of elements. /// /// The sequence of values to transform then sum. /// A transformation function. /// The sum of the transformed elements. public static double Sum(this List source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (selector == null) throw new ArgumentNullException(nameof(selector)); double sum = 0; for (int i = 0; i < source.Count; i++) { sum += selector(source[i]); } return sum; } /// /// Adds a sequence of values. /// /// The sequence to add. /// The sum of the sequence. public static decimal Sum(this List source) { if (source == null) throw new ArgumentNullException(nameof(source)); decimal sum = 0; for (int i = 0; i < source.Count; i++) { sum += source[i]; } return sum; } /// /// Adds the transformed sequence of elements. /// /// The sequence of values to transform then sum. /// A transformation function. /// The sum of the transformed elements. public static decimal Sum(this List source, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (selector == null) throw new ArgumentNullException(nameof(selector)); decimal sum = 0; for (int i = 0; i < source.Count; i++) { sum += selector(source[i]); } return sum; } } } ================================================ FILE: VirtueSky/Linq/Sum.cs.meta ================================================ fileFormatVersion: 2 guid: a400c981f3bcb7544825ed19bd6795f9 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Linq/Take.cs ================================================ using System; using System.Collections.Generic; namespace VirtueSky.Linq { public static partial class L { /// /// Returns a specified number of contiguous elements from the start of a sequence. /// /// The sequence to return elements from. /// The number of elements to return. /// A sequence that contains the specified number of elements from the start of the input sequence. public static T[] Take(this T[] source, int count) { if (source == null) throw new ArgumentNullException(nameof(source)); if (count < 0) { count = 0; } else if (count > source.Length) { count = source.Length; } var result = new T[count]; Array.Copy(source, 0, result, 0, count); return result; } /// /// Returns elements from a sequence as long as a specified condition is true. /// /// A sequence to return elements from. /// A function to test each element for a condition. /// A sequence that contains the elements from the input sequence that occur before the element at which the test no longer passes. public static T[] TakeWhile(this T[] source, Func predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); int count = 0; for (; count < source.Length; count++) { if (!predicate(source[count])) break; } var result = new T[count]; Array.Copy(source, 0, result, 0, count); return result; } /// /// 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. /// /// The sequence to return elements from. /// A function to test each source element for a condition; the second parameter of the function represents the index of the source element. /// A sequence that contains elements from the input sequence that occur before the element at which the test no longer passes. public static T[] TakeWhile(this T[] source, Func predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); int count = 0; for (; count < source.Length; count++) { if (!predicate(source[count], count)) break; } var result = new T[count]; Array.Copy(source, 0, result, 0, count); return result; } /*---- spans ---- */ #if UNITY_2021_3_OR_NEWER /// /// Returns a specified number of contiguous elements from the start of a sequence. /// /// The sequence to return elements from. /// The number of elements to return. /// A sequence that contains the specified number of elements from the start of the input sequence. public static T[] Take(this Span source, int count) { if (source == null) throw new ArgumentNullException(nameof(source)); if (count < 0) { count = 0; } else if (count > source.Length) { count = source.Length; } var result = new T[count]; for (int i = 0; i < result.Length; i++) { result[i] = source[i]; } return result; } /// /// Returns elements from a sequence as long as a specified condition is true. /// /// A sequence to return elements from. /// A function to test each element for a condition. /// A sequence that contains the elements from the input sequence that occur before the element at which the test no longer passes. public static T[] TakeWhile(this Span source, Func predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); int count = 0; for (; count < source.Length; count++) { if (!predicate(source[count])) break; } var result = new T[count]; for (int i = 0; i < result.Length; i++) { result[i] = source[i]; } return result; } /// /// 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. /// /// The sequence to return elements from. /// A function to test each source element for a condition; the second parameter of the function represents the index of the source element. /// A sequence that contains elements from the input sequence that occur before the element at which the test no longer passes. public static T[] TakeWhile(this Span source, Func predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); int count = 0; for (; count < source.Length; count++) { if (!predicate(source[count], count)) break; } var result = new T[count]; for (int i = 0; i < result.Length; i++) { result[i] = source[i]; } return result; } #endif // ------------- Lists ---------------- /// /// Returns a specified number of contiguous elements from the start of a sequence. /// /// The sequence to return elements from. /// The number of elements to return. /// A sequence that contains the specified number of elements from the start of the input sequence. public static List Take(this List source, int count) { if (source == null) throw new ArgumentNullException(nameof(source)); if (count < 0) { count = 0; } else if (count > source.Count) { count = source.Count; } var result = new List(count); for (int i = 0; i < count; i++) { result.Add(source[i]); } return result; } /// /// Returns elements from a sequence as long as a specified condition is true. /// /// A sequence to return elements from. /// A function to test each element for a condition. /// A sequence that contains the elements from the input sequence that occur before the element at which the test no longer passes. public static List TakeWhile(this List source, Func predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); var result = new List(); for (int i = 0; i < source.Count; i++) { if (predicate(source[i])) { result.Add(source[i]); } else { return result; } } return result; } /// /// 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. /// /// The sequence to return elements from. /// A function to test each source element for a condition; the second parameter of the function represents the index of the source element. /// A sequence that contains elements from the input sequence that occur before the element at which the test no longer passes. public static List TakeWhile(this List source, Func predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); var result = new List(); for (int i = 0; i < source.Count; i++) { if (predicate(source[i], i)) result.Add(source[i]); else return result; } return result; } } } ================================================ FILE: VirtueSky/Linq/Take.cs.meta ================================================ fileFormatVersion: 2 guid: 0cc2e55e421b8744b8e07aac567cd8f1 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Linq/Utils/ComparerMagic.cs ================================================ using System; using System.Collections.Generic; using System.Runtime.CompilerServices; namespace VirtueSky.Linq { //Takes a comparer, and creates a reverse comparer, for Descending sorts internal sealed class ComparerReverser : IComparer { private readonly IComparer _wrappedComparer; public ComparerReverser(IComparer wrappedComparer) { this._wrappedComparer = wrappedComparer; } #if !(UNITY_4 || UNITY_5) [MethodImpl(MethodImplOptions.AggressiveInlining)] #endif public int Compare(T x, T y) { return _wrappedComparer.Compare(y, x); } } internal static class ComparerExtensions { // Lets us reverse a comparere with comparer.Reverse(); public static IComparer Reverse(this IComparer comparer) { return new ComparerReverser(comparer); } } internal sealed class LambdaComparer : IComparer { IComparer _comparer; Func _selector; public LambdaComparer(Func selector, IComparer comparer) { this._comparer = comparer; this._selector = selector; } #if !(UNITY_4 || UNITY_5) [MethodImpl(MethodImplOptions.AggressiveInlining)] #endif public int Compare(T x, T y) { return _comparer.Compare(_selector(x), _selector(y)); } } internal sealed class ReverseLambdaComparer : IComparer { IComparer _comparer; Func _selector; public ReverseLambdaComparer(Func selector, IComparer comparer) { this._comparer = comparer; this._selector = selector; } #if !(UNITY_4 || UNITY_5) [MethodImpl(MethodImplOptions.AggressiveInlining)] #endif public int Compare(T x, T y) { return _comparer.Compare(_selector(y), _selector(x)); } } } ================================================ FILE: VirtueSky/Linq/Utils/ComparerMagic.cs.meta ================================================ fileFormatVersion: 2 guid: 66557ee940d37f34aab35fea89d904df MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Linq/Utils/CustomPartition.cs ================================================ using System; using System.Collections.Concurrent; using System.Collections.Generic; namespace VirtueSky.Linq { public class EmptyOrderablePartitioner : OrderablePartitioner { // Constructor just grabs the collection to wrap public EmptyOrderablePartitioner() : base(true, true, true) { } public override IList>> GetOrderablePartitions(int partitionCount) { return new List>>(); } public override IEnumerable> GetOrderableDynamicPartitions() { return new List>(); } // Must be set to true if GetDynamicPartitions() is supported. public override bool SupportsDynamicPartitions { get { return true; } } } internal static class CustomPartition { public static OrderablePartitioner> MakePartition(int len, int? batchSize) { if (len == 0) return new EmptyOrderablePartitioner>(); if (batchSize == null) { return Partitioner.Create(0, len); } else { return Partitioner.Create(0, len, batchSize.Value); } } public static OrderablePartitioner> MakeSimdPartition(int len, int chunkSize, int? batchSize) { if (len == 0) return new EmptyOrderablePartitioner>(); int chunkLen = len - len % chunkSize; int numChunks = chunkLen / chunkSize; if (batchSize == null) { return Partitioner.Create(0, numChunks, numChunks / Environment.ProcessorCount); } else { return Partitioner.Create(0, numChunks, batchSize.Value); } } } } ================================================ FILE: VirtueSky/Linq/Utils/CustomPartition.cs.meta ================================================ fileFormatVersion: 2 guid: dde1a3193124a35428d1cb52f5911b07 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Linq/Utils/GenericOperators.cs ================================================ using System; using System.Runtime.CompilerServices; /* C# has no way to constrain a generic to only primitive types. You can only constrain them to value types via: where T : struct All primitives are value types but not all value types are primitives. Thus, when you try to do operations like + > < == on generic value types, you get a compiler error. These methods work around that by checking the type, casting, and performing the operation. The JIT elides all of the non relevant bits of the If statement for each generic type, so this is remarkably still fast. Since these are only used for the SIMD specific operations, and the SIMD library works exactly this way as well, it does not add any problems that don't already exist when you use .NET SIMD. Which is, if you create a Vector where T is a non primitive value type, you will get a runtime error. */ namespace VirtueSky.Linq { internal static class GenericOperators { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static T Add(T a, T b) { if (typeof(T) == typeof(byte)) { return (T)(object)((byte)(object)a + (byte)(object)b); } if (typeof(T) == typeof(sbyte)) { return (T)(object)((sbyte)(object)a + (sbyte)(object)b); } if (typeof(T) == typeof(ushort)) { return (T)(object)((ushort)(object)a + (ushort)(object)b); } if (typeof(T) == typeof(short)) { return (T)(object)((short)(object)a + (short)(object)b); } if (typeof(T) == typeof(uint)) { return (T)(object)((uint)(object)a + (uint)(object)b); } if (typeof(T) == typeof(int)) { return (T)(object)((int)(object)a + (int)(object)b); } if (typeof(T) == typeof(ulong)) { return (T)(object)((ulong)(object)a + (ulong)(object)b); } if (typeof(T) == typeof(long)) { return (T)(object)((long)(object)a + (long)(object)b); } if (typeof(T) == typeof(float)) { return (T)(object)((float)(object)a + (float)(object)b); } if (typeof(T) == typeof(double)) { return (T)(object)((double)(object)a + (double)(object)b); } throw new NotSupportedException("Nope"); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool GreaterThan(T a, T b) { if (typeof(T) == typeof(byte)) { return ((byte)(object)a > (byte)(object)b); } if (typeof(T) == typeof(sbyte)) { return ((sbyte)(object)a > (sbyte)(object)b); } if (typeof(T) == typeof(ushort)) { return ((ushort)(object)a > (ushort)(object)b); } if (typeof(T) == typeof(short)) { return ((short)(object)a > (short)(object)b); } if (typeof(T) == typeof(uint)) { return ((uint)(object)a > (uint)(object)b); } if (typeof(T) == typeof(int)) { return ((int)(object)a > (int)(object)b); } if (typeof(T) == typeof(ulong)) { return ((ulong)(object)a > (ulong)(object)b); } if (typeof(T) == typeof(long)) { return ((long)(object)a > (long)(object)b); } if (typeof(T) == typeof(float)) { return ((float)(object)a > (float)(object)b); } if (typeof(T) == typeof(double)) { return ((double)(object)a > (double)(object)b); } throw new NotSupportedException("Nope"); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Equals(T a, T b) { if (typeof(T) == typeof(byte)) { return ((byte)(object)a == (byte)(object)b); } if (typeof(T) == typeof(sbyte)) { return ((sbyte)(object)a == (sbyte)(object)b); } if (typeof(T) == typeof(ushort)) { return ((ushort)(object)a == (ushort)(object)b); } if (typeof(T) == typeof(short)) { return ((short)(object)a == (short)(object)b); } if (typeof(T) == typeof(uint)) { return ((uint)(object)a == (uint)(object)b); } if (typeof(T) == typeof(int)) { return ((int)(object)a == (int)(object)b); } if (typeof(T) == typeof(ulong)) { return ((ulong)(object)a == (ulong)(object)b); } if (typeof(T) == typeof(long)) { return ((long)(object)a == (long)(object)b); } if (typeof(T) == typeof(float)) { return ((float)(object)a == (float)(object)b); } if (typeof(T) == typeof(double)) { return ((double)(object)a == (double)(object)b); } throw new NotSupportedException("Nope"); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool LessThan(T a, T b) { if (typeof(T) == typeof(byte)) { return ((byte)(object)a < (byte)(object)b); } if (typeof(T) == typeof(sbyte)) { return ((sbyte)(object)a < (sbyte)(object)b); } if (typeof(T) == typeof(ushort)) { return ((ushort)(object)a < (ushort)(object)b); } if (typeof(T) == typeof(short)) { return ((short)(object)a < (short)(object)b); } if (typeof(T) == typeof(uint)) { return ((uint)(object)a < (uint)(object)b); } if (typeof(T) == typeof(int)) { return ((int)(object)a < (int)(object)b); } if (typeof(T) == typeof(ulong)) { return ((ulong)(object)a < (ulong)(object)b); } if (typeof(T) == typeof(long)) { return ((long)(object)a < (long)(object)b); } if (typeof(T) == typeof(float)) { return ((float)(object)a < (float)(object)b); } if (typeof(T) == typeof(double)) { return ((double)(object)a < (double)(object)b); } throw new NotSupportedException("Nope"); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Divide(T a, double b) { if (typeof(T) == typeof(byte)) { return (double)(object)((byte)(object)a / b); } if (typeof(T) == typeof(sbyte)) { return (double)(object)((sbyte)(object)a / b); } if (typeof(T) == typeof(ushort)) { return (double)(object)((ushort)(object)a / b); } if (typeof(T) == typeof(short)) { return (double)(object)((short)(object)a / b); } if (typeof(T) == typeof(uint)) { return (double)(object)((uint)(object)a / b); } if (typeof(T) == typeof(int)) { return (double)(object)((int)(object)a / b); } if (typeof(T) == typeof(ulong)) { return (double)(object)((ulong)(object)a / b); } if (typeof(T) == typeof(long)) { return (double)(object)((long)(object)a / b); } if (typeof(T) == typeof(float)) { return (double)(object)((float)(object)a / b); } if (typeof(T) == typeof(double)) { return (double)(object)((double)(object)a / b); } throw new NotSupportedException("Nope"); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float DivideFloat(T a, float b) { if (typeof(T) == typeof(byte)) { return (float)(object)((byte)(object)a / b); } if (typeof(T) == typeof(sbyte)) { return (float)(object)((sbyte)(object)a / b); } if (typeof(T) == typeof(ushort)) { return (float)(object)((ushort)(object)a / b); } if (typeof(T) == typeof(short)) { return (float)(object)((short)(object)a / b); } if (typeof(T) == typeof(uint)) { return (float)(object)((uint)(object)a / b); } if (typeof(T) == typeof(int)) { return (float)(object)((int)(object)a / b); } if (typeof(T) == typeof(ulong)) { return (float)(object)((ulong)(object)a / b); } if (typeof(T) == typeof(long)) { return (float)(object)((long)(object)a / b); } if (typeof(T) == typeof(float)) { return (float)(object)((float)(object)a / b); } if (typeof(T) == typeof(double)) { return (float)(object)((double)(object)a / b); } throw new NotSupportedException("Nope"); } } } ================================================ FILE: VirtueSky/Linq/Utils/GenericOperators.cs.meta ================================================ fileFormatVersion: 2 guid: fe36c4d7b07bf2e4bb00c45caf6c9996 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Linq/Utils/SliceHelper.cs ================================================ using System; namespace VirtueSky.Linq { public static class SliceHelper { #if UNITY_2021_3_OR_NEWER public static Span Slice(this T[] array, int start, int len) { return array.AsSpan().Slice(start, len); } #endif } } ================================================ FILE: VirtueSky/Linq/Utils/SliceHelper.cs.meta ================================================ fileFormatVersion: 2 guid: 619337f0dba031740b61516a6273a48d MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Linq/Utils.meta ================================================ fileFormatVersion: 2 guid: bb0d335b166120842bf598442f1444cd folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Linq/VirtueSky.Sunflower.Linq.asmdef ================================================ { "name": "VirtueSky.Sunflower.Linq", "rootNamespace": "", "references": [], "includePlatforms": [], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], "versionDefines": [], "noEngineReferences": false } ================================================ FILE: VirtueSky/Linq/VirtueSky.Sunflower.Linq.asmdef.meta ================================================ fileFormatVersion: 2 guid: efdee36e63e4ce34a91071531ec746c1 AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Linq/Where.cs ================================================ using System; using System.Collections.Generic; namespace VirtueSky.Linq { public static partial class L { // -------------------------- ARRAYS -------------------------------------------- /// /// Filters a sequence of values based on a predicate. /// /// A sequence to filter. /// A function to test each element for a condition. /// A sequence that contains elements from the input sequence that satisfy the condition. public static T[] Filter(this T[] source, Func predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); T[] result = new T[source.Length]; int idx = 0; for (int i = 0; i < source.Length; i++) { if (predicate(source[i])) { result[idx] = source[i]; idx++; } } Array.Resize(ref result, idx); return result; } /// /// Filters a sequence of values based on a predicate that includes the index in it's logic. /// /// A sequence to filter. /// A function to test each element for a condition along with the element's index. /// A sequence that contains elements from the input sequence that satisfy the condition. public static T[] Filter(this T[] source, Func predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); T[] result = new T[source.Length]; int idx = 0; for (int i = 0; i < source.Length; i++) { if (predicate(source[i], i)) { result[idx] = source[i]; idx++; } } Array.Resize(ref result, idx); return result; } // -------------------------- Spans -------------------------------------------- #if UNITY_2021_3_OR_NEWER /// /// Filters a sequence of values based on a predicate. /// /// A sequence to filter. /// A function to test each element for a condition. /// A sequence that contains elements from the input sequence that satisfy the condition. public static T[] Filter(this Span source, Func predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); T[] result = new T[source.Length]; int idx = 0; for (int i = 0; i < source.Length; i++) { if (predicate(source[i])) { result[idx] = source[i]; idx++; } } Array.Resize(ref result, idx); return result; } /// /// Filters a sequence of values based on a predicate that includes the index in it's logic. /// /// A sequence to filter. /// A function to test each element for a condition along with the element's index. /// A sequence that contains elements from the input sequence that satisfy the condition. public static T[] Filter(this Span source, Func predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); T[] result = new T[source.Length]; int idx = 0; for (int i = 0; i < source.Length; i++) { if (predicate(source[i], i)) { result[idx] = source[i]; idx++; } } Array.Resize(ref result, idx); return result; } #endif // -------------------------- LISTS -------------------------------------------- /// /// Filters a sequence of values based on a predicate. /// /// A sequence to filter. /// A function to test each element for a condition. /// A sequence that contains elements from the input sequence that satisfy the condition. public static List Filter(this List source, Predicate predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); return source.FindAll(predicate); } /// /// Filters a sequence of values based on a predicate that includes the index in it's logic. /// /// A sequence to filter. /// A function to test each element for a condition along with the element's index. /// A sequence that contains elements from the input sequence that satisfy the condition. public static List Filter(this List source, Func predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); List r = new List(); for (int i = 0; i < source.Count; i++) { if (predicate(source[i], i)) r.Add(source[i]); } return r; } } } ================================================ FILE: VirtueSky/Linq/Where.cs.meta ================================================ fileFormatVersion: 2 guid: 1b05f1b5de1c9034ea282fb161088459 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Linq/WhereAggregate.cs ================================================ using System; using System.Collections.Generic; namespace VirtueSky.Linq { public static partial class L { // ----------------------------- Arrays ------------------ /// /// Combines Where and Aggregate for optimal performance /// /// The input to filter then aggregate. /// The function to filter the input sequence with. /// The function to aggregate the filtered sequence. /// The filtered then aggregated sequence. public static T FilterReduce(this T[] source, Func predicate, Func func) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); if (func == null) throw new ArgumentNullException(nameof(func)); var result = default(T); int i = 0; for (; i < source.Length; i++) { if (predicate(source[i])) { result = source[i]; i++; break; } } for (; i < source.Length; i++) { if (predicate(source[i])) { result = func(result, source[i]); } } return result; } /// /// Combines Where and Aggregate with index for optimal performance /// /// The input to filter then aggregate. /// The function to filter the input sequence and it's index with. /// The function to aggregate the filtered sequence. /// The filtered then aggregated sequence. public static T FilterReduce(this T[] source, Func predicate, Func func) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); var result = default(T); int i = 0; for (; i < source.Length; i++) { if (predicate(source[i], i)) { result = source[i]; i++; break; } } for (; i < source.Length; i++) { if (predicate(source[i], i)) { result = func(result, source[i]); } } return result; } /// /// Combines Where and Aggregate for optimal performance with a starting seed. /// /// The input to filter then aggregate. /// The function to filter the input sequence with. /// The initial value to aggregate on. /// The function to aggregate the filtered sequence. /// The filtered then aggregated sequence. public static TAccumulate FilterReduce( this TSource[] source, Func predicate, TAccumulate seed, Func func) { if (source == null) throw new ArgumentNullException(nameof(source)); if (func == null) throw new ArgumentNullException(nameof(func)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); TAccumulate result = seed; foreach (var v in source) { if (predicate(v)) result = func(result, v); } return result; } /// /// Combines Where and Aggregate for optimal performance with a starting seed and a result transformation. /// /// The input to filter then aggregate. /// The function to filter the input sequence with. /// The initial value to aggregate on. /// The function to aggregate the filtered sequence. /// A function to transform the final result. /// The filtered then aggregated then transformed sequence. public static TResult FilterReduce( this TSource[] source, Func predicate, TAccumulate seed, Func func, Func resultSelector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (func == null) throw new ArgumentNullException(nameof(func)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector)); TAccumulate result = seed; //int count = 0; foreach (var v in source) { if (predicate(v)) { result = func(result, v); //count++; } } return resultSelector(result); } // ----------------------------- Spans ------------------ #if UNITY_2021_3_OR_NEWER /// /// Combines Where and Aggregate for optimal performance /// /// The input to filter then aggregate. /// The function to filter the input sequence with. /// The function to aggregate the filtered sequence. /// The filtered then aggregated sequence. public static T FilterReduce(this Span source, Func predicate, Func func) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); if (func == null) throw new ArgumentNullException(nameof(func)); var result = default(T); int i = 0; for (; i < source.Length; i++) { if (predicate(source[i])) { result = source[i]; i++; break; } } for (; i < source.Length; i++) { if (predicate(source[i])) { result = func(result, source[i]); } } return result; } /// /// Combines Where and Aggregate with index for optimal performance /// /// The input to filter then aggregate. /// The function to filter the input sequence and it's index with. /// The function to aggregate the filtered sequence. /// The filtered then aggregated sequence. public static T FilterReduce(this Span source, Func predicate, Func func) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); var result = default(T); int i = 0; for (; i < source.Length; i++) { if (predicate(source[i], i)) { result = source[i]; i++; break; } } for (; i < source.Length; i++) { if (predicate(source[i], i)) { result = func(result, source[i]); } } return result; } /// /// Combines Where and Aggregate for optimal performance with a starting seed. /// /// The input to filter then aggregate. /// The function to filter the input sequence with. /// The initial value to aggregate on. /// The function to aggregate the filtered sequence. /// The filtered then aggregated sequence. public static TAccumulate FilterReduce( this Span source, Func predicate, TAccumulate seed, Func func) { if (source == null) throw new ArgumentNullException(nameof(source)); if (func == null) throw new ArgumentNullException(nameof(func)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); TAccumulate result = seed; foreach (var v in source) { if (predicate(v)) result = func(result, v); } return result; } /// /// Combines Where and Aggregate for optimal performance with a starting seed and a result transformation. /// /// The input to filter then aggregate. /// The function to filter the input sequence with. /// The initial value to aggregate on. /// The function to aggregate the filtered sequence. /// A function to transform the final result. /// The filtered then aggregated then transformed sequence. public static TResult FilterReduce( this Span source, Func predicate, TAccumulate seed, Func func, Func resultSelector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (func == null) throw new ArgumentNullException(nameof(func)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector)); TAccumulate result = seed; //int count = 0; foreach (var v in source) { if (predicate(v)) { result = func(result, v); //count++; } } return resultSelector(result); } #endif // --------------------------- Lists ------------------------- /// /// Combines Where and Aggregate for optimal performance /// /// The input to filter then aggregate. /// The function to filter the input sequence with. /// The function to aggregate the filtered sequence. /// The filtered then aggregated sequence. public static T FilterReduce(this List source, Func predicate, Func func) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); if (func == null) throw new ArgumentNullException(nameof(func)); var result = default(T); int i = 0; for (; i < source.Count; i++) { if (predicate(source[i])) { result = source[i]; i++; break; } } for (; i < source.Count; i++) { if (predicate(source[i])) { result = func(result, source[i]); } } return result; } /// /// Combines Where and Aggregate with index for optimal performance /// /// The input to filter then aggregate. /// The function to filter the input sequence and it's index with. /// The function to aggregate the filtered sequence. /// The filtered then aggregated sequence. public static T FilterReduce(this List source, Func predicate, Func func) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); var result = default(T); int i = 0; for (; i < source.Count; i++) { if (predicate(source[i], i)) { result = source[i]; i++; break; } } for (; i < source.Count; i++) { if (predicate(source[i], i)) { result = func(result, source[i]); } } return result; } /// /// Combines Where and Aggregate for optimal performance with a starting seed. /// /// The input to filter then aggregate. /// The function to filter the input sequence with. /// The initial value to aggregate on. /// The function to aggregate the filtered sequence. /// The filtered then aggregated sequence. public static TAccumulate FilterReduce( this List source, Func predicate, TAccumulate seed, Func func) { if (source == null) throw new ArgumentNullException(nameof(source)); if (func == null) throw new ArgumentNullException(nameof(func)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); TAccumulate result = seed; for (int i = 0; i < source.Count; i++) { var v = source[i]; if (predicate(v)) result = func(result, v); } return result; } /// /// Combines Where and Aggregate for optimal performance with a starting seed and a result transformation. /// /// The input to filter then aggregate. /// The function to filter the input sequence with. /// The initial value to aggregate on. /// The function to aggregate the filtered sequence. /// A function to transform the final result. /// The filtered then aggregated then transformed sequence. public static TResult FilterReduce( this List source, Func predicate, TAccumulate seed, Func func, Func resultSelector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (func == null) throw new ArgumentNullException(nameof(func)); if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector)); TAccumulate result = seed; for (int i = 0; i < source.Count; i++) { var v = source[i]; if (predicate(v)) result = func(result, v); } return resultSelector(result); } } } ================================================ FILE: VirtueSky/Linq/WhereAggregate.cs.meta ================================================ fileFormatVersion: 2 guid: d9218245a4e42c14698c87b135829153 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Linq/WhereSelect.cs ================================================ using System; using System.Collections.Generic; namespace VirtueSky.Linq { public static partial class L { // -------------------------- ARRAYS -------------------------------------------- /// /// Combined Where and Select for optimal performance. /// /// The input sequence to filter then transform. /// A function to use to filter the sequence. /// A function to transform the filtered elements. /// A sequence of filtered and transformed elements. public static TResult[] FilterMap(this T[] source, Func predicate, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); if (selector == null) throw new ArgumentNullException(nameof(selector)); var result = new TResult[source.Length]; int idx = 0; for (int i = 0; i < source.Length; i++) { if (predicate(source[i])) { result[idx] = selector(source[i]); idx++; } } Array.Resize(ref result, idx); return result; } /// /// Combined Where and Select for optimal performance that uses the index in the /// predicate and selector. /// /// The input sequence to filter then transform. /// A function to use to filter the sequence. /// A function to transform the filtered elements. /// A sequence of filtered and transformed elements. public static TResult[] FilterMap(this T[] source, Func predicate, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); if (selector == null) throw new ArgumentNullException(nameof(selector)); var result = new TResult[source.Length]; int idx = 0; for (int i = 0; i < source.Length; i++) { if (predicate(source[i], i)) { result[idx] = selector(source[i], idx); idx++; } } Array.Resize(ref result, idx); return result; } // -------------------------- SPANS -------------------------------------------- #if UNITY_2021_3_OR_NEWER /// /// Combined Where and Select for optimal performance. /// /// The input sequence to filter then transform. /// A function to use to filter the sequence. /// A function to transform the filtered elements. /// A sequence of filtered and transformed elements. public static TResult[] FilterMap(this Span source, Func predicate, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); if (selector == null) throw new ArgumentNullException(nameof(selector)); var result = new TResult[source.Length]; int idx = 0; for (int i = 0; i < source.Length; i++) { if (predicate(source[i])) { result[idx] = selector(source[i]); idx++; } } Array.Resize(ref result, idx); return result; } /// /// Combined Where and Select for optimal performance that uses the index in the /// predicate and selector. /// /// The input sequence to filter then transform. /// A function to use to filter the sequence. /// A function to transform the filtered elements. /// A sequence of filtered and transformed elements. public static TResult[] FilterMap(this Span source, Func predicate, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); if (selector == null) throw new ArgumentNullException(nameof(selector)); var result = new TResult[source.Length]; int idx = 0; for (int i = 0; i < source.Length; i++) { if (predicate(source[i], i)) { result[idx] = selector(source[i], idx); idx++; } } Array.Resize(ref result, idx); return result; } #endif // -------------------------- LISTS -------------------------------------------- /// /// Combined Where and Select for optimal performance. /// /// The input sequence to filter then transform. /// A function to use to filter the sequence. /// A function to transform the filtered elements. /// A sequence of filtered and transformed elements. public static List FilterMap(this List source, Func predicate, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); if (selector == null) throw new ArgumentNullException(nameof(selector)); var r = new List(); for (int i = 0; i < source.Count; i++) { if (predicate(source[i])) r.Add(selector(source[i])); } return r; } /// /// Combined Where and Select for optimal performance that uses the index in the /// predicate and selector. /// /// The input sequence to filter then transform. /// A function to use to filter the sequence. /// A function to transform the filtered elements. /// A sequence of filtered and transformed elements. public static List FilterMap(this List source, Func predicate, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (predicate == null) throw new ArgumentNullException(nameof(predicate)); if (selector == null) throw new ArgumentNullException(nameof(selector)); var r = new List(); int idx = 0; for (int i = 0; i < source.Count; i++) { if (predicate(source[i], i)) { r.Add(selector(source[i], idx)); idx++; } } return r; } } } ================================================ FILE: VirtueSky/Linq/WhereSelect.cs.meta ================================================ fileFormatVersion: 2 guid: 18a368bd1cc38d945a0010693a2f4913 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Linq/WhereSum.cs ================================================ using System; using System.Collections.Generic; namespace VirtueSky.Linq { public static partial class L { // -------------------------- ARRAYS -------------------------------------------- /// /// Adds the values in the sequence that match the where predicate. /// /// The sequence to add. /// A function to filter the sequence with before summing. /// The sum of the sequence. public static int FilterSum(this int[] source, Func predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); int sum = 0; checked { foreach (var v in source) { if (predicate(v)) { sum += v; } } } return sum; } /// /// Performs a filter with the where predicate, then sums the transformed values. /// /// The sequence of values to transform then sum. /// A function to filter the sequence with before summing. /// A transformation function. /// The sum of the transformed elements. public static int FilterSum(this T[] source, Func predicate, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (selector == null) throw new ArgumentNullException(nameof(selector)); int sum = 0; checked { foreach (var v in source) { if (predicate(v)) { sum += selector(v); } } } return sum; } /// /// Adds the values in the sequence that match the where predicate. /// /// The sequence to add. /// A function to filter the sequence with before summing. /// The sum of the sequence. public static long FilterSum(this long[] source, Func predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); long sum = 0; checked { foreach (var v in source) { if (predicate(v)) { sum += v; } } } return sum; } /// /// Performs a filter with the where predicate, then sums the transformed values. /// /// The sequence of values to transform then sum. /// A function to filter the sequence with before summing. /// A transformation function. /// The sum of the transformed elements. public static long FilterSum(this T[] source, Func predicate, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (selector == null) throw new ArgumentNullException(nameof(selector)); long sum = 0; checked { foreach (var v in source) { if (predicate(v)) { sum += selector(v); } } } return sum; } /// /// Adds the values in the sequence that match the where predicate. /// /// The sequence to add. /// A function to filter the sequence with before summing. /// The sum of the sequence. public static float FilterSum(this float[] source, Func predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); double sum = 0; foreach (var v in source) { if (predicate(v)) { sum += v; } } return (float)sum; } /// /// Performs a filter with the where predicate, then sums the transformed values. /// /// The sequence of values to transform then sum. /// A function to filter the sequence with before summing. /// A transformation function. /// The sum of the transformed elements. public static float FilterSum(this T[] source, Func predicate, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (selector == null) throw new ArgumentNullException(nameof(selector)); double sum = 0; foreach (var v in source) { if (predicate(v)) { sum += selector(v); } } return (float)sum; } /// /// Adds the values in the sequence that match the where predicate. /// /// The sequence to add. /// A function to filter the sequence with before summing. /// The sum of the sequence. public static double FilterSum(this double[] source, Func predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); double sum = 0; foreach (var v in source) { if (predicate(v)) { sum += v; } } return sum; } /// /// Performs a filter with the where predicate, then sums the transformed values. /// /// The sequence of values to transform then sum. /// A function to filter the sequence with before summing. /// A transformation function. /// The sum of the transformed elements. public static double FilterSum(this T[] source, Func predicate, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (selector == null) throw new ArgumentNullException(nameof(selector)); double sum = 0; foreach (var v in source) { if (predicate(v)) { sum += selector(v); } } return sum; } /// /// Adds the values in the sequence that match the where predicate. /// /// The sequence to add. /// A function to filter the sequence with before summing. /// The sum of the sequence. public static decimal FilterSum(this decimal[] source, Func predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); decimal sum = 0; foreach (var v in source) { if (predicate(v)) { sum += v; } } return sum; } /// /// Performs a filter with the where predicate, then sums the transformed values. /// /// The sequence of values to transform then sum. /// A function to filter the sequence with before summing. /// A transformation function. /// The sum of the transformed elements. public static decimal FilterSum(this T[] source, Func predicate, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (selector == null) throw new ArgumentNullException(nameof(selector)); decimal sum = 0; foreach (var v in source) { if (predicate(v)) { sum += selector(v); } } return sum; } // -------------------------- SPANS -------------------------------------------- #if UNITY_2021_3_OR_NEWER /// /// Adds the values in the sequence that match the where predicate. /// /// The sequence to add. /// A function to filter the sequence with before summing. /// The sum of the sequence. public static int FilterSum(this Span source, Func predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); int sum = 0; checked { foreach (var v in source) { if (predicate(v)) { sum += v; } } } return sum; } /// /// Performs a filter with the where predicate, then sums the transformed values. /// /// The sequence of values to transform then sum. /// A function to filter the sequence with before summing. /// A transformation function. /// The sum of the transformed elements. public static int FilterSum(this Span source, Func predicate, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (selector == null) throw new ArgumentNullException(nameof(selector)); int sum = 0; checked { foreach (var v in source) { if (predicate(v)) { sum += selector(v); } } } return sum; } /// /// Adds the values in the sequence that match the where predicate. /// /// The sequence to add. /// A function to filter the sequence with before summing. /// The sum of the sequence. public static long FilterSum(this Span source, Func predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); long sum = 0; checked { foreach (var v in source) { if (predicate(v)) { sum += v; } } } return sum; } /// /// Performs a filter with the where predicate, then sums the transformed values. /// /// The sequence of values to transform then sum. /// A function to filter the sequence with before summing. /// A transformation function. /// The sum of the transformed elements. public static long FilterSum(this Span source, Func predicate, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (selector == null) throw new ArgumentNullException(nameof(selector)); long sum = 0; checked { foreach (var v in source) { if (predicate(v)) { sum += selector(v); } } } return sum; } /// /// Adds the values in the sequence that match the where predicate. /// /// The sequence to add. /// A function to filter the sequence with before summing. /// The sum of the sequence. public static float FilterSum(this Span source, Func predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); double sum = 0; foreach (var v in source) { if (predicate(v)) { sum += v; } } return (float)sum; } /// /// Performs a filter with the where predicate, then sums the transformed values. /// /// The sequence of values to transform then sum. /// A function to filter the sequence with before summing. /// A transformation function. /// The sum of the transformed elements. public static float FilterSum(this Span source, Func predicate, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (selector == null) throw new ArgumentNullException(nameof(selector)); double sum = 0; foreach (var v in source) { if (predicate(v)) { sum += selector(v); } } return (float)sum; } /// /// Adds the values in the sequence that match the where predicate. /// /// The sequence to add. /// A function to filter the sequence with before summing. /// The sum of the sequence. public static double FilterSum(this Span source, Func predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); double sum = 0; foreach (var v in source) { if (predicate(v)) { sum += v; } } return sum; } /// /// Performs a filter with the where predicate, then sums the transformed values. /// /// The sequence of values to transform then sum. /// A function to filter the sequence with before summing. /// A transformation function. /// The sum of the transformed elements. public static double FilterSum(this Span source, Func predicate, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (selector == null) throw new ArgumentNullException(nameof(selector)); double sum = 0; foreach (var v in source) { if (predicate(v)) { sum += selector(v); } } return sum; } /// /// Adds the values in the sequence that match the where predicate. /// /// The sequence to add. /// A function to filter the sequence with before summing. /// The sum of the sequence. public static decimal FilterSum(this Span source, Func predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); decimal sum = 0; foreach (var v in source) { if (predicate(v)) { sum += v; } } return sum; } /// /// Performs a filter with the where predicate, then sums the transformed values. /// /// The sequence of values to transform then sum. /// A function to filter the sequence with before summing. /// A transformation function. /// The sum of the transformed elements. public static decimal FilterSum(this Span source, Func predicate, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (selector == null) throw new ArgumentNullException(nameof(selector)); decimal sum = 0; foreach (var v in source) { if (predicate(v)) { sum += selector(v); } } return sum; } #endif // -------------------------- LISTS -------------------------------------------- /// /// Adds the values in the sequence that match the where predicate. /// /// The sequence to add. /// A function to filter the sequence with before summing. /// The sum of the sequence. public static int FilterSum(this List source, Func predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); int sum = 0; checked { for (int i = 0; i < source.Count; i++) { var s = source[i]; if (predicate(s)) { sum += s; } } } return sum; } /// /// Performs a filter with the where predicate, then sums the transformed values. /// /// The sequence of values to transform then sum. /// A function to filter the sequence with before summing. /// A transformation function. /// The sum of the transformed elements. public static int FilterSum(this List source, Func predicate, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (selector == null) throw new ArgumentNullException(nameof(selector)); int sum = 0; checked { for (int i = 0; i < source.Count; i++) { var s = source[i]; if (predicate(s)) { sum += selector(s); } } } return sum; } /// /// Adds the values in the sequence that match the where predicate. /// /// The sequence to add. /// A function to filter the sequence with before summing. /// The sum of the sequence. public static long FilterSum(this List source, Func predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); long sum = 0; checked { for (int i = 0; i < source.Count; i++) { var s = source[i]; if (predicate(s)) { sum += s; } } } return sum; } /// /// Performs a filter with the where predicate, then sums the transformed values. /// /// The sequence of values to transform then sum. /// A function to filter the sequence with before summing. /// A transformation function. /// The sum of the transformed elements. public static long FilterSum(this List source, Func predicate, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (selector == null) throw new ArgumentNullException(nameof(selector)); long sum = 0; checked { for (int i = 0; i < source.Count; i++) { var s = source[i]; if (predicate(s)) { sum += selector(s); } } } return sum; } /// /// Adds the values in the sequence that match the where predicate. /// /// The sequence to add. /// A function to filter the sequence with before summing. /// The sum of the sequence. public static float FilterSum(this List source, Func predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); double sum = 0; for (int i = 0; i < source.Count; i++) { var s = source[i]; if (predicate(s)) { sum += s; } } return (float)sum; } /// /// Performs a filter with the where predicate, then sums the transformed values. /// /// The sequence of values to transform then sum. /// A function to filter the sequence with before summing. /// A transformation function. /// The sum of the transformed elements. public static float FilterSum(this List source, Func predicate, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (selector == null) throw new ArgumentNullException(nameof(selector)); double sum = 0; for (int i = 0; i < source.Count; i++) { var s = source[i]; if (predicate(s)) { sum += selector(s); } } return (float)sum; } /// /// Adds the values in the sequence that match the where predicate. /// /// The sequence to add. /// A function to filter the sequence with before summing. /// The sum of the sequence. public static double FilterSum(this List source, Func predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); double sum = 0; for (int i = 0; i < source.Count; i++) { var s = source[i]; if (predicate(s)) { sum += s; } } return sum; } /// /// Performs a filter with the where predicate, then sums the transformed values. /// /// The sequence of values to transform then sum. /// A function to filter the sequence with before summing. /// A transformation function. /// The sum of the transformed elements. public static double FilterSum(this List source, Func predicate, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (selector == null) throw new ArgumentNullException(nameof(selector)); double sum = 0; for (int i = 0; i < source.Count; i++) { var s = source[i]; if (predicate(s)) { sum += selector(s); } } return sum; } /// /// Adds the values in the sequence that match the where predicate. /// /// The sequence to add. /// A function to filter the sequence with before summing. /// The sum of the sequence. public static decimal FilterSum(this List source, Func predicate) { if (source == null) throw new ArgumentNullException(nameof(source)); decimal sum = 0; for (int i = 0; i < source.Count; i++) { var s = source[i]; if (predicate(s)) { sum += s; } } return sum; } /// /// Performs a filter with the where predicate, then sums the transformed values. /// /// The sequence of values to transform then sum. /// A function to filter the sequence with before summing. /// A transformation function. /// The sum of the transformed elements. public static decimal FilterSum(this List source, Func predicate, Func selector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (selector == null) throw new ArgumentNullException(nameof(selector)); decimal sum = 0; for (int i = 0; i < source.Count; i++) { var s = source[i]; if (predicate(s)) { sum += selector(s); } } return sum; } } } ================================================ FILE: VirtueSky/Linq/WhereSum.cs.meta ================================================ fileFormatVersion: 2 guid: 496c880709ba6b14db9943ce8ba50b3c MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Linq/Zip.cs ================================================ using System; using System.Collections.Generic; namespace VirtueSky.Linq { public static partial class L { /// /// Applies a specified function to the corresponding elements of two sequences, producing a sequence of the results. /// /// The first sequence to merge. /// The second sequence to merge. /// A function that specifies how to merge the elements from the two sequences. /// A sequence that contains merged elements of two input sequences. public static TR[] ZipF(this T[] first, TU[] second, Func selector) { if (first == null) throw new ArgumentNullException(nameof(first)); if (second == null) throw new ArgumentNullException(nameof(second)); if (selector == null) throw new ArgumentNullException(nameof(selector)); //maintain array bounds elision if (first.Length < second.Length) { var result = new TR[first.Length]; for (int i = 0; i < first.Length; i++) { result[i] = selector(first[i], second[i]); } return result; } else { var result = new TR[second.Length]; for (int i = 0; i < second.Length; i++) { result[i] = selector(first[i], second[i]); } return result; } } #if UNITY_2021_3_OR_NEWER /// /// Applies a specified function to the corresponding elements of two sequences, producing a sequence of the results. /// /// The first sequence to merge. /// The second sequence to merge. /// A function that specifies how to merge the elements from the two sequences. /// A sequence that contains merged elements of two input sequences. public static TR[] ZipF(this Span first, Span second, Func selector) { if (first == null) throw new ArgumentNullException(nameof(first)); if (second == null) throw new ArgumentNullException(nameof(second)); if (selector == null) throw new ArgumentNullException(nameof(selector)); //maintain array bounds elision if (first.Length < second.Length) { var result = new TR[first.Length]; for (int i = 0; i < first.Length; i++) { result[i] = selector(first[i], second[i]); } return result; } else { var result = new TR[second.Length]; for (int i = 0; i < second.Length; i++) { result[i] = selector(first[i], second[i]); } return result; } } #endif /// /// Applies a specified function to the corresponding elements of two sequences, producing a sequence of the results. /// /// The first sequence to merge. /// The second sequence to merge. /// A function that specifies how to merge the elements from the two sequences. /// A sequence that contains merged elements of two input sequences. public static List ZipF(this List first, List second, Func selector) { if (first == null) throw new ArgumentNullException(nameof(first)); if (second == null) throw new ArgumentNullException(nameof(second)); if (selector == null) throw new ArgumentNullException(nameof(selector)); //maintain array bounds elision if (first.Count < second.Count) { var result = new List(first.Count); for (int i = 0; i < first.Count; i++) { result.Add(selector(first[i], second[i])); } return result; } else { var result = new List(second.Count); for (int i = 0; i < second.Count; i++) { result.Add(selector(first[i], second[i])); } return result; } } } } ================================================ FILE: VirtueSky/Linq/Zip.cs.meta ================================================ fileFormatVersion: 2 guid: c469cf6005aaf3246ac1a8251a93c4ce MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Linq.meta ================================================ fileFormatVersion: 2 guid: 0aada19fe3bc91940be0410901475254 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Localization/Editor/AssetTreeViewItem.cs ================================================ using VirtueSky.Localization; using UnityEditor.IMGUI.Controls; namespace VirtueSky.LocalizationEditor { public class AssetTreeViewItem : TreeViewItem { private bool _isDirty; /// /// Gets or sets item as dirty. Added "*" postfix to the display name if is dirty. /// public bool IsDirty { get => _isDirty; set { _isDirty = value; if (value) { displayName = Asset.name + "*"; } else { displayName = Asset.name; } } } public ScriptableLocaleBase Asset { get; private set; } public AssetTreeViewItem(int depth, ScriptableLocaleBase data) : base(data.GetInstanceID(), depth, data.name) { Asset = data; } } } ================================================ FILE: VirtueSky/Localization/Editor/AssetTreeViewItem.cs.meta ================================================ fileFormatVersion: 2 guid: 3161e46b9f8f4d3fab4bbe3958378a1a timeCreated: 1700795837 ================================================ FILE: VirtueSky/Localization/Editor/CsvSerialization.cs ================================================ using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text.RegularExpressions; using VirtueSky.Localization; using UnityEditor; using UnityEngine; namespace VirtueSky.LocalizationEditor { public class CsvSerialization { private const string KEY_COLUMN = "Key"; public void Serialize(Stream stream) { var languages = LocaleSettings.AvailableLanguages; var localizedTexts = Locale.FindAllLocalizedAssets(); using (var writer = new StreamWriter(stream)) { // Write key column. writer.Write(DoubleQuote(KEY_COLUMN)); if (languages.Count > 0) writer.Write(","); // Write used language columns. for (var i = 0; i < languages.Count; i++) { writer.Write(DoubleQuote("{0} ({1})"), languages[i].Code, languages[i].Name); if (i != languages.Count - 1) writer.Write(","); } writer.WriteLine(); // Write localized assets. foreach (var localizedText in localizedTexts) { // Write key. writer.Write(DoubleQuote(localizedText.name)); if (languages.Count > 0) writer.Write(","); for (var i = 0; i < languages.Count; i++) { if (!localizedText.TryGetLocaleValue(languages[i], out string value)) value = ""; writer.Write(DoubleQuote(value)); if (i != languages.Count - 1) writer.Write(","); } writer.WriteLine(); } } } public void Deserialize(Stream stream) { string importLocation = LocaleSettings.ImportLocation; var localizedTexts = Locale.FindAllLocalizedAssets(); using (var reader = new StreamReader(stream)) { var languages = ReadImportLanguages(reader); while (!reader.EndOfStream) { string[] tokens = ReadNextTokens(reader); if (tokens.Length != languages.Count + 1) throw new IOException("Invalid row"); string key = tokens[0]; if (string.IsNullOrEmpty(key)) throw new IOException("Key field must not be empty"); var localizedText = localizedTexts.FirstOrDefault(x => x.name == key); if (localizedText == null) { localizedText = ScriptableObject.CreateInstance(); string assetPath = Path.Combine(importLocation, $"{key}.asset"); AssetDatabase.CreateAsset(localizedText, assetPath); AssetDatabase.SaveAssets(); } // Read languages by ignoring first column (Key). for (var i = 1; i < tokens.Length; i++) { ScriptableLocaleEditor.AddOrUpdateLocale(localizedText, languages[i - 1], tokens[i]); } EditorUtility.SetDirty(localizedText); } } AssetDatabase.Refresh(); } private string[] ReadNextTokens(StreamReader reader) { var line = ""; do { if (line.Length != 0) line += "\n"; line += reader.ReadLine(); } while (!reader.EndOfStream && line.Length > 0 && line[^1] != '\"'); if (line != null) { string[] tokens = Regex.Split(line, @""","""); if (tokens.Length > 0) { string token = tokens[0]; if (token.Length > 0 && token[0] == '\"') token = token.Remove(0, 1); tokens[0] = token; } if (tokens.Length > 1) { string token = tokens[^1]; if (token.Length > 0 && token[^1] == '\"') token = token.Remove(token.Length - 1, 1); tokens[^1] = token; } return tokens; } return Array.Empty(); } private List ReadImportLanguages(StreamReader reader) { var availableLanguages = LocaleSettings.AllLanguages; var importLanguages = new List(); string[] columnTokens = ReadNextTokens(reader); if (columnTokens.Length == 0) { throw new IOException("Column size must be greater than zero"); } // Read languages by ignoring first column (Key). for (var i = 1; i < columnTokens.Length; i++) { string token = columnTokens[i].Trim(); if (token.Length == 0) throw new IOException("Invalid language code column"); // Read only language code. // Emit language name if exist. string[] tokens = token.Split(' '); if (tokens.Length > 0) token = tokens[0].Trim(); var language = availableLanguages.FirstOrDefault(x => x.Code == token); if (language == null) { Debug.LogWarning("Language code (" + token + ") not exist in localization system."); } // Add null language as well to maintain order. importLanguages.Add(language); } return importLanguages; } private static string DoubleQuote(string s) { return $"\"{s}\""; } } } ================================================ FILE: VirtueSky/Localization/Editor/CsvSerialization.cs.meta ================================================ fileFormatVersion: 2 guid: 899f85cc067e4f04e8e16cbffc6493ae MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Localization/Editor/EditorMenu.cs ================================================ using VirtueSky.Localization; using UnityEditor; using UnityEngine; namespace VirtueSky.LocalizationEditor { public static class EditorMenu { private const string MENU_NAME = "Sunflower/Localization/Change Locale/"; [MenuItem("Sunflower/Localization/Import CSV", priority = 10000)] private static void ImportCsv() { LocaleEditorUtil.Import(); } [MenuItem("Sunflower/Localization/Export CSV", priority = 10001)] private static void ExportCsv() { LocaleEditorUtil.Export(); } private static void SetLanguage(Language currentLanguage) { if (!Application.isPlaying) { Debug.LogWarning("Setting language only available when application is playing."); return; } var previousLanguage = Locale.CurrentLanguage; Locale.CurrentLanguage = currentLanguage; Menu.SetChecked(GetMenuName(previousLanguage), false); Menu.SetChecked(GetMenuName(currentLanguage), true); } [MenuItem(MENU_NAME + "/Afrikaans", priority = 10002)] private static void ChangeToAfrikaans() { SetLanguage(Language.Afrikaans); } [MenuItem(MENU_NAME + "/Arabic", priority = 10003)] private static void ChangeToArabic() { SetLanguage(Language.Arabic); } [MenuItem(MENU_NAME + "/Basque", priority = 10003)] private static void ChangeToBasque() { SetLanguage(Language.Basque); } [MenuItem(MENU_NAME + "/Belarusian", priority = 10004)] private static void ChangeToBelarusian() { SetLanguage(Language.Belarusian); } [MenuItem(MENU_NAME + "/Bulgarian", priority = 10005)] private static void ChangeToBulgarian() { SetLanguage(Language.Bulgarian); } [MenuItem(MENU_NAME + "/Catalan", priority = 10006)] private static void ChangeToCatalan() { SetLanguage(Language.Catalan); } [MenuItem(MENU_NAME + "/Chinese", priority = 10007)] private static void ChangeToChinese() { SetLanguage(Language.Chinese); } [MenuItem(MENU_NAME + "/Czech", priority = 10008)] private static void ChangeToCzech() { SetLanguage(Language.Czech); } [MenuItem(MENU_NAME + "/Danish", priority = 10009)] private static void ChangeToDanish() { SetLanguage(Language.Danish); } [MenuItem(MENU_NAME + "/Dutch", priority = 10010)] private static void ChangeToDutch() { SetLanguage(Language.Dutch); } [MenuItem(MENU_NAME + "/English", priority = 10011)] private static void ChangeToEnglish() { SetLanguage(Language.English); } [MenuItem(MENU_NAME + "/Estonian", priority = 10012)] private static void ChangeToEstonian() { SetLanguage(Language.Estonian); } [MenuItem(MENU_NAME + "/Faroese", priority = 10013)] private static void ChangeToFaroese() { SetLanguage(Language.Faroese); } [MenuItem(MENU_NAME + "/Finnish", priority = 10014)] private static void ChangeToFinnish() { SetLanguage(Language.Finnish); } [MenuItem(MENU_NAME + "/French", priority = 10015)] private static void ChangeToFrench() { SetLanguage(Language.French); } [MenuItem(MENU_NAME + "/German", priority = 10016)] private static void ChangeToGerman() { SetLanguage(Language.German); } [MenuItem(MENU_NAME + "/Greek", priority = 10017)] private static void ChangeToGreek() { SetLanguage(Language.Greek); } [MenuItem(MENU_NAME + "/Hebrew", priority = 10018)] private static void ChangeToHebrew() { SetLanguage(Language.Hebrew); } [MenuItem(MENU_NAME + "/Hungarian", priority = 10019)] private static void ChangeToHungarian() { SetLanguage(Language.Hungarian); } [MenuItem(MENU_NAME + "/Icelandic", priority = 10020)] private static void ChangeToIcelandic() { SetLanguage(Language.Icelandic); } [MenuItem(MENU_NAME + "/Indonesian", priority = 10021)] private static void ChangeToIndonesian() { SetLanguage(Language.Indonesian); } [MenuItem(MENU_NAME + "/Italian", priority = 10022)] private static void ChangeToItalian() { SetLanguage(Language.Italian); } [MenuItem(MENU_NAME + "/Japanese", priority = 10023)] private static void ChangeToJapanese() { SetLanguage(Language.Japanese); } [MenuItem(MENU_NAME + "/Korean", priority = 10024)] private static void ChangeToKorean() { SetLanguage(Language.Korean); } [MenuItem(MENU_NAME + "/Latvian", priority = 10025)] private static void ChangeToLatvian() { SetLanguage(Language.Latvian); } [MenuItem(MENU_NAME + "/Lithuanian", priority = 10026)] private static void ChangeToLithuanian() { SetLanguage(Language.Lithuanian); } [MenuItem(MENU_NAME + "/Norwegian", priority = 10027)] private static void ChangeToNorwegian() { SetLanguage(Language.Norwegian); } [MenuItem(MENU_NAME + "/Polish", priority = 10028)] private static void ChangeToPolish() { SetLanguage(Language.Polish); } [MenuItem(MENU_NAME + "/Portuguese", priority = 10029)] private static void ChangeToPortuguese() { SetLanguage(Language.Portuguese); } [MenuItem(MENU_NAME + "/Romanian", priority = 10030)] private static void ChangeToRomanian() { SetLanguage(Language.Romanian); } [MenuItem(MENU_NAME + "/Russian", priority = 10031)] private static void ChangeToRussian() { SetLanguage(Language.Russian); } [MenuItem(MENU_NAME + "/SerboCroatian", priority = 10032)] private static void ChangeToSerboCroatian() { SetLanguage(Language.SerboCroatian); } [MenuItem(MENU_NAME + "/Slovak", priority = 10033)] private static void ChangeToSlovak() { SetLanguage(Language.Slovak); } [MenuItem(MENU_NAME + "/Slovenian", priority = 10034)] private static void ChangeToSlovenian() { SetLanguage(Language.Slovenian); } [MenuItem(MENU_NAME + "/Spanish", priority = 10035)] private static void ChangeToSpanish() { SetLanguage(Language.Spanish); } [MenuItem(MENU_NAME + "/Swedish", priority = 10036)] private static void ChangeToSwedish() { SetLanguage(Language.Swedish); } [MenuItem(MENU_NAME + "/Thai", priority = 10037)] private static void ChangeToThai() { SetLanguage(Language.Thai); } [MenuItem(MENU_NAME + "/Turkish", priority = 10038)] private static void ChangeToTurkish() { SetLanguage(Language.Turkish); } [MenuItem(MENU_NAME + "/Ukrainian", priority = 10039)] private static void ChangeToUkrainian() { SetLanguage(Language.Ukrainian); } [MenuItem(MENU_NAME + "/Vietnamese", priority = 10040)] private static void ChangeToVietnamese() { SetLanguage(Language.Vietnamese); } private static string GetMenuName(Language language) { return $"{MENU_NAME}{language}"; } } } ================================================ FILE: VirtueSky/Localization/Editor/EditorMenu.cs.meta ================================================ fileFormatVersion: 2 guid: 0cb9834b9f274079a170e563944dcc6d timeCreated: 1700818210 ================================================ FILE: VirtueSky/Localization/Editor/LanguagePropertyDrawer.cs ================================================ using VirtueSky.Localization; using UnityEditor; using UnityEngine; namespace VirtueSky.LocalizationEditor { [CustomPropertyDrawer(typeof(Language))] public class LanguagePropertyDrawer : PropertyDrawer { public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { LocaleEditorUtil.LanguageField(position, property, label); } } } ================================================ FILE: VirtueSky/Localization/Editor/LanguagePropertyDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: 28602a5b2f3740e6a50673f383d2b162 timeCreated: 1701069715 ================================================ FILE: VirtueSky/Localization/Editor/LocaleEditorUtil.cs ================================================ using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; using VirtueSky.Localization; using UnityEditor; using UnityEngine; using VirtueSky.UtilsEditor; namespace VirtueSky.LocalizationEditor { public static class LocaleEditorUtil { public static void LocaleDrawLanguageField(Rect position, ref LocaleTreeViewItem localeItem, bool showOnlyBuiltin = false) { var languages = new List(); languages.AddRange(Language.BuiltInLanguages); if (!showOnlyBuiltin) languages.AddRange(GetCustomLanguages()); int currentValueIndex = -1; for (int i = 0; i < languages.Count; i++) { if (languages[i].Code == localeItem.LocaleItem.Language.Code) { currentValueIndex = i; break; } } if (currentValueIndex < 0) { currentValueIndex = languages.FindIndex(x => x.Code == Language.English.Code); Debug.Assert(currentValueIndex >= 0); } int newValueIndex = currentValueIndex; if (GUI.Button(position, languages[currentValueIndex].Name, EditorStyles.popup)) { var searchWindow = ExSearchWindow.Create("Choose Language"); foreach (var lang in languages) { var cache = lang; var item = localeItem; searchWindow.AddEntry(lang.Name, () => { newValueIndex = languages.FindIndex(x => x.Code == cache.Code); if (newValueIndex != currentValueIndex) item.LocaleItem.Language = languages[newValueIndex]; }); } searchWindow.Open(position); } } public static void LanguageField(Rect position, SerializedProperty property, GUIContent label, bool showOnlyBuiltin = false) { var languages = new List(); languages.AddRange(Language.BuiltInLanguages); if (!showOnlyBuiltin) languages.AddRange(GetCustomLanguages()); EditorGUI.BeginProperty(position, label, property); var languageName = property.FindPropertyRelative("name"); var languageCode = property.FindPropertyRelative("code"); int currentValueIndex = languages.FindIndex(x => x.Code == languageCode.stringValue); if (currentValueIndex < 0) { currentValueIndex = languages.FindIndex(x => x == Language.English); Debug.Assert(currentValueIndex >= 0); } if (GUI.Button(position, languages[currentValueIndex].Name, EditorStyles.popup)) { var searchWindow = ExSearchWindow.Create("Choose Language"); foreach (var lang in languages) { var cache = lang; searchWindow.AddEntry(lang.Name, () => { int newValue = languages.FindIndex(x => x.Code == cache.Code); if (newValue != currentValueIndex) { languageName.stringValue = languages[newValue].Name; languageCode.stringValue = languages[newValue].Code; property.serializedObject.ApplyModifiedProperties(); } }); } searchWindow.Open(position); } EditorGUI.EndProperty(); } private static Language[] GetCustomLanguages() { if (LocaleSettings.Instance != null) { var customLanguages = LocaleSettings.AvailableLanguages.Where(x => x.Custom); return customLanguages.ToArray(); } return Array.Empty(); } public static Language GetLanguageValueFromProperty(SerializedProperty languageProperty) { var nameProperty = languageProperty.FindPropertyRelative("name"); if (nameProperty == null) throw new ArgumentException("Language.Name property could not be found"); var codeProperty = languageProperty.FindPropertyRelative("code"); if (codeProperty == null) throw new ArgumentException("Language.Code property could not be found"); var customProperty = languageProperty.FindPropertyRelative("custom"); if (customProperty == null) throw new ArgumentException("Language.Custom property could not be found"); return new Language(nameProperty.stringValue, codeProperty.stringValue, customProperty.boolValue); } public static void SetLanguageProperty(SerializedProperty languageProperty, string name, string code, bool custom) { var nameProperty = languageProperty.FindPropertyRelative("name"); if (nameProperty == null) throw new ArgumentException("Language.Name property could not be found"); var codeProperty = languageProperty.FindPropertyRelative("code"); if (codeProperty == null) throw new ArgumentException("Language.Code property could not be found"); var customProperty = languageProperty.FindPropertyRelative("custom"); if (customProperty == null) throw new ArgumentException("Language.Custom property could not be found"); nameProperty.stringValue = name; codeProperty.stringValue = code; customProperty.boolValue = custom; } public static void SetLanguageProperty(SerializedProperty languageProperty, Language language) { SetLanguageProperty(languageProperty, language.Name, language.Code, language.Custom); } /// /// Import CSV file /// public static void Import() { string path = EditorUtility.OpenFilePanel("Import CSV file", "", "csv"); if (string.IsNullOrEmpty(path)) { return; } try { using (var stream = File.OpenRead(path)) { var serialization = new CsvSerialization(); serialization.Deserialize(stream); } Debug.Log("CSV file has been imported."); } catch (Exception e) { Debug.LogError(e); } } /// /// Export CSV file /// public static void Export() { string fileName = Application.productName + "-" + DateTime.Now.ToString("dd-MM-yyyy", CultureInfo.InvariantCulture); string path = EditorUtility.SaveFilePanel("Export CSV file", "", fileName, "csv"); if (string.IsNullOrEmpty(path)) { return; } try { using (var stream = File.OpenWrite(path)) { var serialization = new CsvSerialization(); serialization.Serialize(stream); } Debug.Log("CSV file has been exported to " + path); } catch (Exception e) { Debug.LogError(e); } } } } ================================================ FILE: VirtueSky/Localization/Editor/LocaleEditorUtil.cs.meta ================================================ fileFormatVersion: 2 guid: ad507e22275a4b6e9cb15e8d1f64357f timeCreated: 1700737003 ================================================ FILE: VirtueSky/Localization/Editor/LocaleSettingsEditor.cs ================================================ using System.Collections.Generic; using System.IO; using System.Linq; #if VIRTUESKY_BAKINGSHEET using Google.Apis.Auth.OAuth2; using Google.Apis.Drive.v3; using Google.Apis.Services; using Google.Apis.Sheets.v4; #endif using VirtueSky.Localization; using UnityEditor; using UnityEditorInternal; using UnityEngine; using VirtueSky.UtilsEditor; namespace VirtueSky.LocalizationEditor { [CustomEditor(typeof(LocaleSettings), true)] public class LocaleSettingsEditor : Editor { private ReorderableList _reorderableList; private SerializedProperty _avaiableLanguageProperty; private SerializedProperty _detectDeviceLanguageProperty; private SerializedProperty _importLocationProperty; private SerializedProperty _googleTranslateApiKeyProperty; private SerializedProperty _spreadsheetKeyProperty; private SerializedProperty _serviceAccountCredentialProperty; private void Init() { _avaiableLanguageProperty ??= serializedObject.FindProperty("availableLanguages"); _detectDeviceLanguageProperty ??= serializedObject.FindProperty("detectDeviceLanguage"); _importLocationProperty ??= serializedObject.FindProperty("importLocation"); _googleTranslateApiKeyProperty ??= serializedObject.FindProperty("googleTranslateApiKey"); _spreadsheetKeyProperty ??= serializedObject.FindProperty("spreadsheetKey"); _serviceAccountCredentialProperty ??= serializedObject.FindProperty("serviceAccountCredential"); if (_avaiableLanguageProperty != null) { _reorderableList = new ReorderableList(serializedObject, _avaiableLanguageProperty, true, true, true, true) { drawHeaderCallback = OnDrawHeaderCallback, drawElementCallback = OnDrawElementCallback }; _reorderableList.onAddDropdownCallback += OnAddDropdownCallback; _reorderableList.onRemoveCallback += OnRemoveCallback; _reorderableList.onCanRemoveCallback += OnCanRemoveCallback; } } private bool OnCanRemoveCallback(ReorderableList list) { return list.count > 1; } private void OnDrawElementCallback(Rect rect, int index, bool isactive, bool isfocused) { var languageProperty = _reorderableList.serializedProperty.GetArrayElementAtIndex(index); var position = new Rect(rect.x, rect.y + 2, rect.width, EditorGUIUtility.singleLineHeight); bool isCustom = languageProperty.FindPropertyRelative("custom").boolValue; if (isCustom) { var languageName = languageProperty.FindPropertyRelative("name"); var languageCode = languageProperty.FindPropertyRelative("code"); float labelWidth = EditorGUIUtility.labelWidth; EditorGUIUtility.labelWidth = 40; var r1 = new Rect(position.x, position.y, position.width / 2 - 2, position.height); EditorGUI.PropertyField(r1, languageName, new GUIContent(languageName.displayName, "Language name")); EditorGUIUtility.labelWidth = 40; var r2 = new Rect(position.x + r1.width + 4, position.y, position.width / 2 - 2, position.height); EditorGUI.PropertyField(r2, languageCode, new GUIContent(languageCode.displayName, "ISO-639-1 code")); EditorGUIUtility.labelWidth = labelWidth; } else { LocaleEditorUtil.LanguageField(position, languageProperty, GUIContent.none, true); } } private void OnDrawHeaderCallback(Rect rect) { EditorGUI.LabelField(rect, "Available Languages"); } private void OnAddDropdownCallback(Rect buttonrect, ReorderableList list) { var menu = new GenericMenu(); menu.AddItem(new GUIContent("Language", "Adds built-in language."), false, () => { ReorderableList.defaultBehaviours.DoAddButton(list); var languageProperty = list.serializedProperty.GetArrayElementAtIndex(list.index); LocaleEditorUtil.SetLanguageProperty(languageProperty, Language.BuiltInLanguages[0]); serializedObject.ApplyModifiedProperties(); }); menu.AddItem(new GUIContent("Custom language", "Adds custom language."), false, () => { ReorderableList.defaultBehaviours.DoAddButton(list); var languageProperty = list.serializedProperty.GetArrayElementAtIndex(list.index); LocaleEditorUtil.SetLanguageProperty(languageProperty, "", "", true); serializedObject.ApplyModifiedProperties(); }); menu.AddItem(new GUIContent("Adds languages in-use", "Adds by searching used languages in assets."), false, () => { AddUsedLocales(); serializedObject.ApplyModifiedProperties(); }); menu.ShowAsContext(); } private void OnRemoveCallback(ReorderableList list) { var languageProperty = list.serializedProperty.GetArrayElementAtIndex(list.index); var language = LocaleEditorUtil.GetLanguageValueFromProperty(languageProperty); if (language.Custom) { var localizedAssets = Locale.FindAllLocalizedAssets(); if (localizedAssets.Any(x => x.LocaleItems.Any(y => y.Language == language))) { if (!EditorUtility.DisplayDialog("Remove \"" + language + "\" language?", "\"" + language + "\" language is in-use by some localized assets." + " Are you sure to remove?", "Remove", "Cancel")) { return; // Cancelled. } } } ReorderableList.defaultBehaviours.DoRemoveButton(list); } private void AddUsedLocales() { var languages = FindUsedLanguages(); _avaiableLanguageProperty.arraySize = languages.Length; for (var i = 0; i < _avaiableLanguageProperty.arraySize; i++) { var languageProperty = _avaiableLanguageProperty.GetArrayElementAtIndex(i); LocaleEditorUtil.SetLanguageProperty(languageProperty, languages[i]); } } private Language[] FindUsedLanguages() { var languages = new HashSet(); for (var i = 0; i < _avaiableLanguageProperty.arraySize; i++) { languages.Add( LocaleEditorUtil.GetLanguageValueFromProperty(_avaiableLanguageProperty.GetArrayElementAtIndex(i))); } var localizedAssets = Locale.FindAllLocalizedAssets(); foreach (var localizedAsset in localizedAssets) { foreach (var locale in localizedAsset.LocaleItems) { languages.Add(locale.Language); } } return languages.ToArray(); } public override void OnInspectorGUI() { Init(); if (_reorderableList != null) { serializedObject.Update(); EditorGUILayout.Separator(); _reorderableList.DoLayoutList(); EditorGUILayout.PropertyField(_detectDeviceLanguageProperty, true); EditorGUILayout.Separator(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.PrefixLabel(_importLocationProperty.displayName); if (GUILayout.Button(_importLocationProperty.stringValue, EditorStyles.objectField)) { string path = EditorUtility.OpenFolderPanel("Select folder for import location", "Assets/", ""); if (Directory.Exists(path)) { path = "Assets" + path.Replace(Application.dataPath, ""); if (AssetDatabase.IsValidFolder(path)) { _importLocationProperty.stringValue = path; } } } EditorGUILayout.EndHorizontal(); EditorGUILayout.Separator(); EditorGUILayout.PropertyField(_googleTranslateApiKeyProperty); if (string.IsNullOrEmpty(_googleTranslateApiKeyProperty.stringValue)) { EditorGUILayout.HelpBox( "If you want to use Google Translate in editor or in-game, attach the API key file claimed from Google Cloud.", MessageType.Info); } else { if (_googleTranslateApiKeyProperty.stringValue.StartsWith("AIzaSyCdaIrr") && _googleTranslateApiKeyProperty.stringValue.EndsWith("120Dy-mfz6I")) EditorGUILayout.HelpBox("Do not use this key. Replace with your API key", MessageType.Info); } EditorGUILayout.Separator(); #if VIRTUESKY_BAKINGSHEET EditorGUILayout.BeginHorizontal(); EditorGUILayout.PropertyField(_spreadsheetKeyProperty); if (GUILayout.Button("Open", GUILayout.Width(65))) { Application.OpenURL( $"https://docs.google.com/spreadsheets/d/{_spreadsheetKeyProperty.stringValue}"); } GUI.backgroundColor = Uniform.Green; GUI.enabled = !EditorApplication.isCompiling && !SessionState.GetBool("spreasheet_importing", false); if (GUILayout.Button("Import", GUILayout.Width(65))) { if (EditorUtility.DisplayDialog("Import Locale From Spreasheet", "Are you sure you wish import Locale from Spreasheet?\nThis action cannot be reversed.", "Ok", "Cancel")) { ImportFormSpreadsheet(); } } GUI.enabled = true; GUI.backgroundColor = Color.white; EditorGUILayout.EndHorizontal(); #else EditorGUILayout.HelpBox( $"Add scripting define symbols: {ConstantDefineSymbols.VIRTUESKY_BAKINGSHEET} and install sdk to use spread sheet", MessageType.Info); #endif EditorGUILayout.PropertyField(_serviceAccountCredentialProperty, GUILayout.MaxHeight(150)); serializedObject.ApplyModifiedProperties(); } else { base.OnInspectorGUI(); } } private async void ImportFormSpreadsheet() { SessionState.SetBool("spreasheet_importing", true); string importLocation = LocaleSettings.ImportLocation; var localizedTexts = Locale.FindAllLocalizedAssets(); #if VIRTUESKY_BAKINGSHEET using (var service = new SheetsService(new BaseClientService.Initializer { HttpClientInitializer = GoogleCredential.FromJson(_serviceAccountCredentialProperty.stringValue) .CreateScoped(DriveService.Scope.DriveReadonly) })) { var sheetReq = service.Spreadsheets.Get(_spreadsheetKeyProperty.stringValue); sheetReq.Fields = "properties,sheets(properties,data.rowData.values.formattedValue)"; var spreadsheet = await sheetReq.ExecuteAsync(); var languages = new List(); var availableLanguages = LocaleSettings.AllLanguages; foreach (var s in spreadsheet.Sheets) { if (!s.Properties.Title.Equals(Application.productName)) continue; foreach (var g in s.Data) { for (var i = 1; i < g.RowData[0].Values.Count; i++) { string code = g.RowData[0].Values[i].FormattedValue; var language = availableLanguages.FirstOrDefault(x => x.Code == code); if (language == null) Debug.LogWarning("Language code (" + code + ") not exist in localization system."); // Add null language as well to maintain order. languages.Add(language); } for (var i = 1; i < g.RowData.Count; i++) { var row = g.RowData[i].Values; var key = row[0]; var localizedText = localizedTexts.FirstOrDefault(x => x.name == key.FormattedValue); if (localizedText == null) { localizedText = CreateInstance(); string assetPath = Path.Combine(importLocation, $"{key}.asset"); AssetDatabase.CreateAsset(localizedText, assetPath); AssetDatabase.SaveAssets(); } // Read languages by ignoring first column (Key). for (var j = 1; j < row.Count; j++) { ScriptableLocaleEditor.AddOrUpdateLocale(localizedText, languages[j - 1], row[j].FormattedValue); } EditorUtility.SetDirty(localizedText); } } } AssetDatabase.Refresh(); } Debug.Log("[Localization] The import process from spreasheet is complete"); SessionState.SetBool("spreasheet_importing", false); #endif } } } ================================================ FILE: VirtueSky/Localization/Editor/LocaleSettingsEditor.cs.meta ================================================ fileFormatVersion: 2 guid: 67bab48307e34de69ccc4f5778ee8aaa timeCreated: 1700734943 ================================================ FILE: VirtueSky/Localization/Editor/LocaleTreeView.cs ================================================ using System; using System.Collections.Generic; using VirtueSky.Localization; using TMPro; using UnityEditor; using UnityEditor.IMGUI.Controls; using UnityEngine; using UnityEngine.Assertions; namespace VirtueSky.LocalizationEditor { public class LocaleTreeView : TreeView { private enum ColumnType { Type, Name, Language, Value } private int _id; private float _valueFieldWidth; private GUIStyle _textAreaStyle; private Rect _cellRect; public LocaleTreeView(TreeViewState state) : base(state) { } public LocaleTreeView(TreeViewState state, MultiColumnHeader multiColumnHeader) : base(state, multiColumnHeader) { _textAreaStyle = new GUIStyle(EditorStyles.textArea) { wordWrap = true }; rowHeight = 20; columnIndexForTreeFoldouts = 1; showAlternatingRowBackgrounds = true; showBorder = true; customFoldoutYOffset = (20 - EditorGUIUtility.singleLineHeight) * 0.5f; multiColumnHeader.canSort = false; Reload(); } protected override TreeViewItem BuildRoot() { _id = 1; var root = new TreeViewItem { id = 0, depth = -1, displayName = "Root" }; var localizedAssets = Locale.FindAllLocalizedAssets(); var allItems = new List(); // Add localized assets. foreach (var localizedAsset in localizedAssets) { var assetItem = new AssetTreeViewItem(0, localizedAsset); allItems.Add(assetItem); // Add locale items. var localItems = localizedAsset.LocaleItems; for (var i = 0; i < localItems.Length; i++) { allItems.Add(new LocaleTreeViewItem(_id++, 1, localItems[i], assetItem)); } } // Utility method that initializes the TreeViewItem.children and .parent for all items. SetupParentsAndChildrenFromDepths(root, allItems); return root; } protected override void RowGUI(RowGUIArgs args) { for (int i = 0; i < args.GetNumVisibleColumns(); ++i) { var columnType = (ColumnType)args.GetColumn(i); var cellRect = args.GetCellRect(i); CellGUI(cellRect, args.item, columnType, ref args); // Refresh row heights if the Value column width is changed. if (columnType == ColumnType.Value && cellRect.width != _valueFieldWidth) { _valueFieldWidth = cellRect.width; RefreshCustomRowHeights(); } } } /// /// Make TextArea as expandable as possible. /// protected override float GetCustomRowHeight(int row, TreeViewItem item) { float h = base.GetCustomRowHeight(row, item); if (item is LocaleTreeViewItem localeItem) { var assetItem = localeItem.Parent; if (assetItem.Asset.GetGenericType == typeof(string)) { var column = multiColumnHeader.GetColumn(3); if (column != null) { var stringValue = (string)localeItem.LocaleItem.ObjectValue; float calculatedRowHeight = _textAreaStyle.CalcHeight(new GUIContent(stringValue), column.width) + 4; h = Mathf.Clamp(calculatedRowHeight, h, 100); } } } return h; } void CellGUI(Rect cellRect, TreeViewItem item, ColumnType column, ref RowGUIArgs args) { switch (column) { case ColumnType.Type: DrawTypeCell(cellRect, item); break; case ColumnType.Name: DrawNameCell(cellRect, item, ref args); break; case ColumnType.Language: DrawLanguageCell(cellRect, item); break; case ColumnType.Value: DrawValueCell(cellRect, item); break; } } private void DrawTypeCell(Rect cellRect, TreeViewItem item) { CenterRectUsingSingleLineHeight(ref cellRect); var treeViewItem = item as AssetTreeViewItem; if (treeViewItem != null) { Texture icon; // Set icon by localized asset value type. var valueType = treeViewItem.Asset.GetGenericType; if (valueType == typeof(string)) { icon = EditorGUIUtility.ObjectContent(null, typeof(TextAsset)).image; } else if (valueType == typeof(TMP_FontAsset)) { icon = EditorGUIUtility.ObjectContent(null, typeof(Font)).image; } else { icon = EditorGUIUtility.ObjectContent(null, valueType).image; } // Set default icon if not exist. if (!icon) { icon = EditorGUIUtility.ObjectContent(null, typeof(ScriptableObject)).image; } if (icon) { GUI.DrawTexture(cellRect, icon, ScaleMode.ScaleToFit); } } } private void DrawNameCell(Rect cellRect, TreeViewItem item, ref RowGUIArgs args) { ValidateMissingLocales(item); CenterRectUsingSingleLineHeight(ref cellRect); args.rowRect = cellRect; base.RowGUI(args); GUI.contentColor = Color.white; } private void ValidateMissingLocales(TreeViewItem item) { var assetTreeViewItem = item as AssetTreeViewItem; var assetItem = assetTreeViewItem?.Asset; var localizedText = assetItem as LocaleText; if (localizedText == null) return; foreach (var typedLocaleItem in localizedText.TypedLocaleItems) { GUI.contentColor = string.IsNullOrEmpty(typedLocaleItem.Value) ? new Color(0.97f, 0.33f, 0.41f) : Color.white; } } private void DrawLanguageCell(Rect cellRect, TreeViewItem item) { cellRect.y += 2; cellRect.height -= 4; if (item is LocaleTreeViewItem localeItem) { LocaleEditorUtil.LocaleDrawLanguageField(cellRect, ref localeItem); } } private void DrawValueCell(Rect cellRect, TreeViewItem item) { cellRect.y += 2; cellRect.height -= 4; if (item is LocaleTreeViewItem treeViewItem) { var localeItem = treeViewItem.LocaleItem; var valueType = treeViewItem.Parent.Asset.GetGenericType; EditorGUI.BeginChangeCheck(); if (valueType.IsSubclassOf(typeof(UnityEngine.Object))) { if (valueType == typeof(TMP_FontAsset) && localeItem.ObjectValue == null) { localeItem.ObjectValue = EditorGUI.ObjectField(cellRect, null, typeof(TMP_FontAsset), false); } else { localeItem.ObjectValue = EditorGUI.ObjectField(cellRect, (UnityEngine.Object)localeItem.ObjectValue, localeItem.ObjectValue.GetType(), false); } } else if (valueType == typeof(string)) { EditorGUI.BeginChangeCheck(); localeItem.ObjectValue = EditorGUI.TextArea(cellRect, (string)localeItem.ObjectValue, _textAreaStyle); if (EditorGUI.EndChangeCheck()) { RefreshCustomRowHeights(); } } else { EditorGUI.LabelField(cellRect, valueType + " value type not supported."); } if (EditorGUI.EndChangeCheck()) { treeViewItem.Parent.IsDirty = true; EditorUtility.SetDirty(treeViewItem.Parent.Asset); } } } protected override bool CanRename(TreeViewItem item) { if (item is AssetTreeViewItem) { // Only allow rename if we can show the rename overlay with a certain width (label might be clipped // by other columns). var renameRect = GetRenameRect(treeViewRect, 0, item); return renameRect.width > 30; } return false; } protected override void RenameEnded(RenameEndedArgs args) { // Set the backend name and reload the tree to reflect the new model if (args.acceptedRename) { var item = FindItem(args.itemID, rootItem) as AssetTreeViewItem; if (item != null) { string assetPath = AssetDatabase.GetAssetPath(item.Asset.GetInstanceID()); AssetDatabase.RenameAsset(assetPath, args.newName); AssetDatabase.SaveAssets(); Reload(); } } } public TreeViewItem GetSelectedItem() { var selection = GetSelection(); if (selection.Count > 0) { return FindItem(selection[0], rootItem); } return null; } protected override Rect GetRenameRect(Rect rowRect, int row, TreeViewItem item) { var cellRect = GetCellRectForTreeFoldouts(rowRect); CenterRectUsingSingleLineHeight(ref cellRect); return base.GetRenameRect(cellRect, row, item); } public static MultiColumnHeaderState CreateDefaultMultiColumnHeaderState(float treeViewWidth) { var typeColumnWidth = 30; var nameColumnWidth = 150; var languageColumnWidth = 110; float valueColumnWidth = treeViewWidth - typeColumnWidth - nameColumnWidth - languageColumnWidth; var columns = new[] { new MultiColumnHeaderState.Column { headerContent = new GUIContent(EditorGUIUtility.FindTexture("FilterByType"), "Localized asset type."), contextMenuText = "Type", headerTextAlignment = TextAlignment.Center, sortedAscending = true, sortingArrowAlignment = TextAlignment.Center, width = typeColumnWidth, minWidth = 30, maxWidth = 60, autoResize = false, allowToggleVisibility = true }, new MultiColumnHeaderState.Column { headerContent = new GUIContent("Name", "Localized asset name."), headerTextAlignment = TextAlignment.Left, sortedAscending = true, sortingArrowAlignment = TextAlignment.Center, width = nameColumnWidth, minWidth = 60, autoResize = false, allowToggleVisibility = false }, new MultiColumnHeaderState.Column { headerContent = new GUIContent("Language", "Locale language."), headerTextAlignment = TextAlignment.Left, sortedAscending = true, sortingArrowAlignment = TextAlignment.Center, width = languageColumnWidth, minWidth = 35, autoResize = false }, new MultiColumnHeaderState.Column { headerContent = new GUIContent("Value", "Locale value."), headerTextAlignment = TextAlignment.Left, sortedAscending = true, sortingArrowAlignment = TextAlignment.Left, width = valueColumnWidth, minWidth = 60, autoResize = true } }; Assert.AreEqual(columns.Length, Enum.GetValues(typeof(ColumnType)).Length, "Number of columns should match number of enum values: You probably forgot to update one of them."); var state = new MultiColumnHeaderState(columns); return state; } } } ================================================ FILE: VirtueSky/Localization/Editor/LocaleTreeView.cs.meta ================================================ fileFormatVersion: 2 guid: 2bbde9ae865d43eaa3854f73a514867e timeCreated: 1700794399 ================================================ FILE: VirtueSky/Localization/Editor/LocaleTreeViewItem.cs ================================================ using VirtueSky.Localization; using UnityEditor.IMGUI.Controls; namespace VirtueSky.LocalizationEditor { public class LocaleTreeViewItem : TreeViewItem { public LocaleItemBase LocaleItem { get; private set; } public AssetTreeViewItem Parent { get; private set; } public LocaleTreeViewItem(int id, int depth, LocaleItemBase localeItem, AssetTreeViewItem parent) : base(id, depth, "") { LocaleItem = localeItem; Parent = parent; } } } ================================================ FILE: VirtueSky/Localization/Editor/LocaleTreeViewItem.cs.meta ================================================ fileFormatVersion: 2 guid: acf3a9988b6142fba133610d1a86eafa timeCreated: 1700795969 ================================================ FILE: VirtueSky/Localization/Editor/PostBuildProcessor.cs ================================================ using System.Collections.Generic; using VirtueSky.Localization; using UnityEditor; using UnityEditor.Callbacks; #if UNITY_IOS using System.IO; using UnityEngine; using UnityEditor.iOS.Xcode; #endif namespace MyNamespace { public static class PostBuildProcessor { [PostProcessBuild(9999)] public static void OnPostprocessBuild(BuildTarget buildTarget, string pathToBuiltProject) { #if UNITY_IOS if (buildTarget == BuildTarget.iOS) { // Continue if any localization info exists. var localizations = GetLocalizations(); if (localizations.Count == 0) { return; } // Get plist. var plistPath = pathToBuiltProject + "/Info.plist"; var plist = new PlistDocument(); plist.ReadFromString(File.ReadAllText(plistPath)); // Get root of plist/dict. var rootDict = plist.root; var plistLocalizations = rootDict.CreateArray("CFBundleLocalizations"); // Add localizations. foreach (string locale in localizations) { plistLocalizations.AddString(locale); Debug.Log("[LocalizationBuildPostprocessor] Localization added: " + locale); } // Save all changes. File.WriteAllText(plistPath, plist.WriteToString()); } #endif } private static List GetLocalizations() { var localizations = new List(); if (LocaleSettings.Instance != null) { foreach (var language in LocaleSettings.AvailableLanguages) { localizations.Add(language.Code); } } return localizations; } } } ================================================ FILE: VirtueSky/Localization/Editor/PostBuildProcessor.cs.meta ================================================ fileFormatVersion: 2 guid: b0d039b7f39e03b4ba3653ae712de662 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Localization/Editor/ScriptableLocaleEditor.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using VirtueSky.Localization; using UnityEditor; using UnityEditorInternal; using UnityEngine; using VirtueSky.Misc; using VirtueSky.Utils; namespace VirtueSky.LocalizationEditor { [CustomEditor(typeof(ScriptableLocaleBase), true)] [CanEditMultipleObjects] public class ScriptableLocaleEditor : UnityEditor.Editor { private static GoogleTranslator Translator => new(LocaleSettings.GoogleTranslateApiKey); private ReorderableList _reorderable; private SerializedProperty _itemsProperty; private Rect _currentLayoutRect; private GUIStyle _textAreaStyle; private GUIStyle TextAreaStyle { get { return _textAreaStyle ??= new GUIStyle(EditorStyles.textArea) { wordWrap = true }; } } private void OnEnable() { if (target == null) return; var assetValueType = ((ScriptableLocaleBase)target).GetGenericType; _itemsProperty = serializedObject.FindProperty("items"); if (_itemsProperty != null) { _reorderable = new ReorderableList(serializedObject: serializedObject, elements: _itemsProperty, draggable: true, displayHeader: true, displayAddButton: true, displayRemoveButton: true) { drawHeaderCallback = rect => { EditorGUI.LabelField(rect, ObjectNames.NicifyVariableName(target.GetType().Name) + "s"); } }; _reorderable.drawElementCallback = (rect, index, _, _) => { var element = _reorderable.serializedProperty.GetArrayElementAtIndex(index); // Language field. var languageRect = new Rect(rect.x, rect.y + 2, 100, rect.height - 4); var languageProperty = element.FindPropertyRelative("language"); EditorGUI.PropertyField(languageRect, languageProperty, GUIContent.none); // Value field. var valueRect = new Rect(languageRect.x + languageRect.width + 4, languageRect.y, rect.width - languageRect.width - 4, rect.height - 4); var valueProperty = element.FindPropertyRelative("value"); if (assetValueType == typeof(string)) { valueProperty.stringValue = EditorGUI.TextArea(valueRect, valueProperty.stringValue, TextAreaStyle); } else { EditorGUI.PropertyField(valueRect, valueProperty, GUIContent.none); } }; _reorderable.onCanRemoveCallback = list => list.count > 1; _reorderable.elementHeightCallback = index => { var element = _reorderable.serializedProperty.GetArrayElementAtIndex(index); var valueProperty = element.FindPropertyRelative("value"); float elementHeight = EditorGUIUtility.singleLineHeight; if (assetValueType == typeof(string)) { float valueWidth = _currentLayoutRect.width - 100 - 30; elementHeight = TextAreaStyle.CalcHeight(new GUIContent(valueProperty.stringValue), valueWidth); } return Mathf.Max(EditorGUIUtility.singleLineHeight, elementHeight) + 4; }; _reorderable.onAddDropdownCallback = (_, list) => { var menu = new GenericMenu(); menu.AddItem(new GUIContent("Language", "Adds a language."), false, () => { ReorderableList.defaultBehaviours.DoAddButton(list); serializedObject.ApplyModifiedProperties(); }); menu.AddItem(new GUIContent("Add languages from settings", "Adds by searching used languages in assets."), false, () => { AddLanguagesFromSettings(); serializedObject.ApplyModifiedProperties(); }); menu.AddItem(new GUIContent("Add all languages", "Adds all languages."), false, () => { AddAllLanguages(); serializedObject.ApplyModifiedProperties(); }); menu.ShowAsContext(); }; } } public override void OnInspectorGUI() { if (Selection.objects.Length > 1) { EditorGUILayout.HelpBox("Currently does not support editing multiple Locales at the same time. Just choose one", MessageType.Warning); return; } if (_reorderable != null) { _currentLayoutRect = GUILayoutUtility.GetRect(0, _reorderable.GetHeight(), GUILayout.ExpandWidth(true)); serializedObject.Update(); _reorderable.DoList(_currentLayoutRect); serializedObject.ApplyModifiedProperties(); Rect helpRect; if (target is LocaleText localeText) { if (GUILayout.Button("Translate")) { Debug.Log("[Localization] Starting Translate LocaleText: ".SetColor(Color.cyan) + localeText.name); var firstLocale = localeText.TypedLocaleItems.First(); foreach (var locale in localeText.TypedLocaleItems) { if (!string.IsNullOrEmpty(locale.Value)) continue; var localeItem = locale; Translator.Translate(new GoogleTranslateRequest(firstLocale.Language, locale.Language, firstLocale.Value), e => { var response = e.Responses.FirstOrDefault(); if (response != null) { localeItem.Value = response.translatedText; Debug.Log("[Localization] Translate Successfull: ".SetColor(CustomColor.Green) + localeText.name); } EditorUtility.SetDirty(localeText); }, e => { Debug.LogError("Response (" + e.ResponseCode + "): " + e.Message); }); } } if (GUILayout.Button("Fill Language Same Avaiable Language")) { Debug.Log("[Localization] Starting fill language same with AvaiableLanguage for LocaleText!".SetColor(Color.cyan)); foreach (var item in localeText.LocaleItems.ToList()) { var result = localeText.LocaleItems.Select(itemBase => new LocaleItem(itemBase.Language, itemBase.ObjectValue.ToString())).ToList(); // remove duplicate for (var i = 0; i < result.ToList().Count - 1; i++) { var cache = result[i]; for (var j = 0; j < result.ToList().Count; j++) { if (j == i) continue; if (result[j].Language == cache.Language) result.RemoveAt(j); } } int index = Array.FindIndex(localeText.LocaleItems, x => x.Language == item.Language); if (!LocaleSettings.AvailableLanguages.Contains(localeText.LocaleItems[index].Language)) result.RemoveAt(index); localeText.SetLocaleItems(result); } if (localeText.LocaleItems.Length < LocaleSettings.AvailableLanguages.Count) { foreach (var lang in LocaleSettings.AvailableLanguages) { int index = Array.FindIndex(localeText.LocaleItems, x => x.Language == lang); if (index >= 0) continue; AddLocale(localeText); index = localeText.LocaleItems.Length - 1; var localeItem = localeText.LocaleItems[index]; localeItem.Language = lang; localeItem.ObjectValue = ""; } } Debug.Log("[Localization] Fill language same with AvaiableLanguage Successfull: ".SetColor(CustomColor.Green) + localeText.name); } helpRect = _currentLayoutRect; helpRect.y += _reorderable.GetHeight() + 50; } else { helpRect = _currentLayoutRect; helpRect.y += _reorderable.GetHeight() + 4; } helpRect.height = EditorGUIUtility.singleLineHeight * 1.5f; EditorGUI.HelpBox(helpRect, "First locale item is used as fallback if needed.", MessageType.Info); } else { base.OnInspectorGUI(); EditorGUILayout.HelpBox("Make sure that locale items variable name is declared as \"m_LocaleItems\" and it is serializable.", MessageType.Error); } } private void AddAllLanguages() { AddLanguages(LocaleSettings.AllLanguages); } private void AddLanguagesFromSettings() { AddLanguages(LocaleSettings.AvailableLanguages); } private void AddLanguages(List languages) { var filteredLanguages = languages.Where(x => !IsLanguageExist(_itemsProperty, x)).ToArray(); int startIndex = _itemsProperty.arraySize; _itemsProperty.arraySize += filteredLanguages.Length; for (var i = 0; i < filteredLanguages.Length; i++) { var localeItem = _itemsProperty.GetArrayElementAtIndex(startIndex + i); var localeItemValue = localeItem.FindPropertyRelative("value"); switch (localeItemValue.propertyType) { case SerializedPropertyType.String: localeItemValue.stringValue = ""; break; default: localeItemValue.objectReferenceValue = null; break; } var localeItemLanguage = localeItem.FindPropertyRelative("language"); LocaleEditorUtil.SetLanguageProperty(localeItemLanguage, filteredLanguages[i]); } } private static bool IsLanguageExist(SerializedProperty localeItemsProperty, Language language) { for (var i = 0; i < localeItemsProperty.arraySize; i++) { var element = localeItemsProperty.GetArrayElementAtIndex(i); var languageProperty = element.FindPropertyRelative("language"); string languageCode = languageProperty.FindPropertyRelative("code").stringValue; if (languageCode == language.Code) { return true; } } return false; } /// /// Adds a locale and the value or updates if specified language is existing. /// public static bool AddOrUpdateLocale(ScriptableLocaleBase localizedAsset, Language language, object value) { var serializedObject = new SerializedObject(localizedAsset); serializedObject.Update(); var elements = serializedObject.FindProperty("items"); if (elements != null && elements.arraySize > 0) { int index = Array.FindIndex(localizedAsset.LocaleItems, x => x.Language == language); if (index < 0) { AddLocale(localizedAsset); index = localizedAsset.LocaleItems.Length - 1; } var localeItem = localizedAsset.LocaleItems[index]; localeItem.Language = language; localeItem.ObjectValue = value; return true; } return false; } /// /// Adds a locale end of the list by copying last one. /// public static bool AddLocale(ScriptableLocaleBase localizedAsset) { var serializedObject = new SerializedObject(localizedAsset); serializedObject.Update(); var elements = serializedObject.FindProperty("items"); if (elements != null) { elements.arraySize += 1; serializedObject.ApplyModifiedProperties(); return true; } return false; } /// /// Removes specified locale item from the list. /// public static bool RemoveLocale(ScriptableLocaleBase localizedAsset, LocaleItemBase localeItem) { var serializedObject = new SerializedObject(localizedAsset); serializedObject.Update(); var elements = serializedObject.FindProperty("items"); if (elements != null && elements.arraySize > 1) { int index = Array.IndexOf(localizedAsset.LocaleItems, localeItem); if (index >= 0) { elements.DeleteArrayElementAtIndex(index); serializedObject.ApplyModifiedProperties(); return true; } } return false; } } } ================================================ FILE: VirtueSky/Localization/Editor/ScriptableLocaleEditor.cs.meta ================================================ fileFormatVersion: 2 guid: fbf069e56fe04065a9688fb9db098b35 timeCreated: 1700811314 ================================================ FILE: VirtueSky/Localization/Editor/VirtueSky.Sunflower.Localization.Editor.asmdef ================================================ { "name": "VirtueSky.Sunflower.Localization.Editor", "rootNamespace": "", "references": [ "GUID:c7e7793e0b5d326429f90e6fd716775e", "GUID:6055be8ebefd69e48b49212b09b47b2f", "GUID:c282fd4f3fc2c7540914e85842a013c7", "GUID:c904f6d969e991d459a0843b71c22ec5", "GUID:fca7ec166e04dc948b624a983315e2c9" ], "includePlatforms": [ "Editor" ], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], "versionDefines": [], "noEngineReferences": false } ================================================ FILE: VirtueSky/Localization/Editor/VirtueSky.Sunflower.Localization.Editor.asmdef.meta ================================================ fileFormatVersion: 2 guid: 6a3996cca4c689e4597a79d47ef54353 AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Localization/Editor.meta ================================================ fileFormatVersion: 2 guid: 4541ab8d10d0ffd4fa21bf4fa05cd76f folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleAudioClipComponent.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Localization { [EditorIcon("icon_csharp")] public class LocaleAudioClipComponent : LocaleComponentGeneric { } } ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleAudioClipComponent.cs.meta ================================================ fileFormatVersion: 2 guid: 2e7fb96ec2704d6990df46c485ffc81f MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleComponent.cs ================================================ using System; using UnityEngine; namespace VirtueSky.Localization { [ExecuteInEditMode] public abstract class LocaleComponent : MonoBehaviour { private bool _isOnValidate; public event EventHandler LocaleChangedEvent; protected virtual void OnEnable() { ForceUpdate(); if (Application.isPlaying) Locale.LocaleChangedEvent += LocaleChangedInvoke; } private void LocaleChangedInvoke(object sender, LocaleChangedEventArgs e) { ForceUpdate(); } public void ForceUpdate() { if (TryUpdateComponentLocalization(_isOnValidate)) OnLocaleChangedEvent(); _isOnValidate = false; } protected virtual void OnDisable() { if (Application.isPlaying) Locale.LocaleChangedEvent -= LocaleChangedInvoke; } protected virtual void OnLocaleChangedEvent() { LocaleChangedEvent?.Invoke(this, EventArgs.Empty); } /// /// Gets the localized value safely. /// protected static T GetValueOrDefault(LocaleVariable variable) where T : class { return variable ? variable.Value : default; } private void OnValidate() { _isOnValidate = true; ForceUpdate(); } /// /// Updates component localization if possible. /// /// /// Use to update component localization. /// Use this method to override only. /// /// This method is whether called by or not. /// True if component is updated successfully. protected abstract bool TryUpdateComponentLocalization(bool isOnValidate); } } ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleComponent.cs.meta ================================================ fileFormatVersion: 2 guid: 00e8bb0211d8487caaa2330848fa1a30 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleComponentGeneric.cs ================================================ using System; using UnityEngine; namespace VirtueSky.Localization { public class LocaleComponentGeneric : LocaleComponentGenericBase where TVariable : LocaleVariable where T : class { [SerializeField] private TVariable variable; public TVariable Variable { get => variable; set { variable = value; ForceUpdate(); } } protected override Type GetValueType() => typeof(T); protected override bool HasLocaleValue() => Variable != null; protected override object GetLocaleValue() => GetValueOrDefault(variable); } } ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleComponentGeneric.cs.meta ================================================ fileFormatVersion: 2 guid: df7e6a70081d4ba48f8e4eb4eef89afc MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleComponentGenericBase.cs ================================================ using System; using System.Collections.Generic; using System.Reflection; using UnityEngine; using VirtueSky.Core; using VirtueSky.Inspector; namespace VirtueSky.Localization { public abstract class LocaleComponentGenericBase : LocaleComponent { [SerializeField] private Component component; [SerializeField] private Optional property; private PropertyInfo _propertyInfo; private void Awake() { Init(); } private void Init() { if (_propertyInfo == null) TryInitProperty(); } private bool TryInitProperty() { if (component != null) { _propertyInfo = FindProperty(component, property.Value); return _propertyInfo != null; } return false; } public bool TrySetComponentAndProperty(string propertyName) where TComponent : Component { component = GetComponent(); if (component != null) { property = new Optional(false, propertyName); if (!TryInitProperty()) { property = new Optional(false, ""); return false; } return true; } return false; } public bool TrySetComponentAndPropertyIfNotSet(string propertyName) where TComponent : Component { return component == null && TrySetComponentAndProperty(propertyName); } private PropertyInfo FindProperty(Component c, string propertyName) { return c.GetType().GetProperty(propertyName, GetValueType()); } /// /// Finds list of localizable properties of specified component. /// internal List FindProperties(Component component) { var valueType = GetValueType(); var allProperties = component.GetType().GetProperties(); var properties = new List(); foreach (var p in allProperties) { if (p.CanWrite && valueType.IsAssignableFrom(p.PropertyType)) properties.Add(p); } return properties; } protected abstract Type GetValueType(); protected abstract bool HasLocaleValue(); protected abstract object GetLocaleValue(); protected override bool TryUpdateComponentLocalization(bool isOnValidate) { #if UNITY_EDITOR if (!Application.isPlaying) Init(); #endif if (HasLocaleValue() && _propertyInfo != null) { #if UNITY_EDITOR if (!Application.isPlaying) UnityEditor.Undo.RecordObject(component, "locale value changed"); #endif _propertyInfo.SetValue(component, GetLocaleValue(), null); return true; } return false; } } } ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleComponentGenericBase.cs.meta ================================================ fileFormatVersion: 2 guid: c3fd2a3b62114eadaa77be8418bd622c MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleFontComponent.cs ================================================ using TMPro; using UnityEngine; using UnityEngine.UI; using VirtueSky.Inspector; namespace VirtueSky.Localization { [EditorIcon("icon_csharp")] public class LocaleFontComponent : LocaleComponentGeneric { private void Reset() { TrySetComponentAndPropertyIfNotSet("font"); TrySetComponentAndPropertyIfNotSet("font"); } } } ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleFontComponent.cs.meta ================================================ fileFormatVersion: 2 guid: 039bf27d4d5c4d589f834b515f5df93b MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleMaterialComponent.cs ================================================ using TMPro; using VirtueSky.Inspector; namespace VirtueSky.Localization { using UnityEngine; [EditorIcon("icon_csharp")] public class LocaleMaterialComponent : LocaleComponentGeneric { private void Reset() { TrySetComponentAndPropertyIfNotSet("material"); TrySetComponentAndPropertyIfNotSet("fontMaterial"); } } } ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleMaterialComponent.cs.meta ================================================ fileFormatVersion: 2 guid: a2e17a0a9298b014daac3f73685bfd04 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Behaviour/LocalePrefabComponent.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Localization { [EditorIcon("icon_csharp")] public class LocalePrefabComponent : LocaleComponent { public LocalePrefab prefab; private GameObject _instance; protected override bool TryUpdateComponentLocalization(bool isOnValidate) { #if UNITY_EDITOR if (Application.isPlaying && !isOnValidate) { #endif if (prefab) { if (_instance) Destroy(_instance); _instance = Instantiate(prefab.Value, transform); return true; } #if UNITY_EDITOR } #endif return false; } } } ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Behaviour/LocalePrefabComponent.cs.meta ================================================ fileFormatVersion: 2 guid: 948b7b1689814a1f9e6825ee1e7b42b8 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleRendererComponent.cs ================================================ using UnityEngine; using VirtueSky.Inspector; using VirtueSky.Misc; namespace VirtueSky.Localization { [EditorIcon("icon_csharp")] public class LocaleRendererComponent : LocaleComponent { public int materialIndex; public string propertyName = "_MainTex"; public LocaleTexture localeTexture; protected override bool TryUpdateComponentLocalization(bool isOnValidate) { if (localeTexture) { var materials = GetMaterials(); if (materialIndex < materials.Length) { materials[materialIndex].SetTexture(propertyName, GetValueOrDefault(localeTexture)); return true; } Debug.LogWarning("Index out of range : " + materialIndex.ToString()); } return false; } private void OnValidate() { materialIndex = materialIndex.Max(0); } private Material[] GetMaterials() { #if UNITY_EDITOR if (Application.isPlaying) return GetComponent().sharedMaterials; #endif return GetComponent().materials; } } } ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleRendererComponent.cs.meta ================================================ fileFormatVersion: 2 guid: 6ada74822b484d4295211203588c0d95 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleSharedMaterialComponent.cs ================================================ using TMPro; using VirtueSky.Inspector; namespace VirtueSky.Localization { using UnityEngine; [EditorIcon("icon_csharp")] public class LocaleSharedMaterialComponent : LocaleComponentGeneric { private void Reset() { TrySetComponentAndPropertyIfNotSet("sharedMaterial"); TrySetComponentAndPropertyIfNotSet("fontSharedMaterial"); } } } ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleSharedMaterialComponent.cs.meta ================================================ fileFormatVersion: 2 guid: d76ad44851a25a74a918e5ec8039616c MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleSpriteComponent.cs ================================================ using UnityEngine; using UnityEngine.UI; using VirtueSky.Inspector; namespace VirtueSky.Localization { [EditorIcon("icon_csharp")] public class LocaleSpriteComponent : LocaleComponentGeneric { private void Reset() { TrySetComponentAndPropertyIfNotSet("sprite"); } } } ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleSpriteComponent.cs.meta ================================================ fileFormatVersion: 2 guid: 9b94f319fd1343a1abd8936aef0ef5fa MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleTMPFontComponent.cs ================================================ using TMPro; using VirtueSky.Inspector; namespace VirtueSky.Localization { [EditorIcon("icon_csharp")] public class LocaleTMPFontComponent : LocaleComponentGeneric { private void Reset() { TrySetComponentAndPropertyIfNotSet("font"); TrySetComponentAndPropertyIfNotSet("font"); } } } ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleTMPFontComponent.cs.meta ================================================ fileFormatVersion: 2 guid: 476932f1680198544b423513d634d37e MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleTextAssetComponent.cs ================================================ using System; using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Localization { [EditorIcon("icon_csharp")] public class LocaleTextAssetComponent : LocaleComponentGeneric { protected override Type GetValueType() => typeof(string); protected override object GetLocaleValue() => Variable ? Variable.Value.text : null; } } ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleTextAssetComponent.cs.meta ================================================ fileFormatVersion: 2 guid: e728a8082a404697b9c9003c68403e78 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleTextComponent.cs ================================================ using System; using System.Linq; using TMPro; using UnityEngine; using UnityEngine.UI; using VirtueSky.Inspector; namespace VirtueSky.Localization { [EditorIcon("icon_csharp")] public class LocaleTextComponent : LocaleComponentGeneric { [SerializeField] private string[] formatArgs = Array.Empty(); public string[] FormatArgs { get => formatArgs; set { formatArgs = value ?? Array.Empty(); ForceUpdate(); } } public void UpdateArgs(params string[] args) { FormatArgs = args; } protected override object GetLocaleValue() { var value = (string)base.GetLocaleValue(); if (FormatArgs.Length > 0 && !string.IsNullOrEmpty(value)) { return string.Format(value, FormatArgs.Cast().ToArray()); } return value; } private void Reset() { TrySetComponentAndPropertyIfNotSet("text"); TrySetComponentAndPropertyIfNotSet("text"); } } } ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleTextComponent.cs.meta ================================================ fileFormatVersion: 2 guid: e6c43f4ebada4d6ab7202113210604cb MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleTextCompositeComponent.cs ================================================ using System; using System.Linq; using System.Text; using System.Text.RegularExpressions; using TMPro; using UnityEngine; using UnityEngine.UI; using VirtueSky.Inspector; namespace VirtueSky.Localization { [EditorIcon("icon_csharp")] public class LocaleTextCompositeComponent : LocaleComponentGenericBase { [SerializeField] private string seperate = ", "; [SerializeField] private LocaleText[] variables; [SerializeField] private string[] formatArgs = Array.Empty(); public string[] FormatArgs { get => formatArgs; set { formatArgs = value ?? Array.Empty(); ForceUpdate(); } } public LocaleText[] Variables { get => variables; set { variables = value; ForceUpdate(); } } public void UpdateArgs(params string[] args) { FormatArgs = args; } public void UpdateVariables(params LocaleText[] args) { Variables = args; } protected override Type GetValueType() => typeof(string); protected override bool HasLocaleValue() => variables is { Length: > 0 }; protected override object GetLocaleValue() { (string value, int totalArgs) = CompositeString(seperate); if (FormatArgs.Length >= totalArgs && !string.IsNullOrEmpty(value)) { return string.Format(value, FormatArgs.Cast().ToArray()); } return value; } private (string, int) CompositeString(string seperate = ", ") { var index = 0; var result = string.Empty; var stringBuilder = new StringBuilder(); foreach (var text in variables) { string temp = GetValueOrDefault(text); const string pattern = @"{(.*?)}"; int count = Regex.Matches(temp, pattern).OfType().Select(m => m.Value).Distinct().Count(); int j = count - 1 + index; for (int i = count - 1; i >= 0; i--) { stringBuilder.Clear(); stringBuilder.Append("{"); stringBuilder.Append(i); var old = stringBuilder.ToString(); stringBuilder.Clear(); stringBuilder.Append("{"); stringBuilder.Append(j); temp = temp.Replace(old, stringBuilder.ToString()); index++; j--; } stringBuilder.Clear(); if (!string.IsNullOrEmpty(result)) { stringBuilder.Append(result); stringBuilder.Append(seperate); } stringBuilder.Append(temp); result = stringBuilder.ToString(); } return (result, index); } private void Reset() { TrySetComponentAndPropertyIfNotSet("text"); TrySetComponentAndPropertyIfNotSet("text"); } } } ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleTextCompositeComponent.cs.meta ================================================ fileFormatVersion: 2 guid: 70f72d8f5ec175e4f9f6dff221346f2b MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleTextureComponent.cs ================================================ using UnityEngine; using UnityEngine.UI; using VirtueSky.Inspector; namespace VirtueSky.Localization { [EditorIcon("icon_csharp")] public class LocaleTextureComponent : LocaleComponentGeneric { private void Reset() { TrySetComponentAndPropertyIfNotSet("texture"); } } } ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleTextureComponent.cs.meta ================================================ fileFormatVersion: 2 guid: 379fc5901f104995931aeee4aed7bf03 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleTextureMaterialComponent.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Localization { [EditorIcon("icon_csharp")] public class LocaleTextureMaterialComponent : LocaleComponent { public Material material; public string propertyName = "_MainTex"; public LocaleTexture localeTexture; protected override bool TryUpdateComponentLocalization(bool isOnValidate) { if (material != null && localeTexture != null) { material.SetTexture(propertyName, GetValueOrDefault(localeTexture)); return true; } return false; } } } ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleTextureMaterialComponent.cs.meta ================================================ fileFormatVersion: 2 guid: cdb3c045afde41f2b8e4185820cb0fba MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleVideoClipComponent.cs ================================================ using UnityEngine.Video; using VirtueSky.Inspector; namespace VirtueSky.Localization { [EditorIcon("icon_csharp")] public class LocaleVideoClipComponent : LocaleComponentGeneric { private void Reset() { TrySetComponentAndPropertyIfNotSet("video"); } } } ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleVideoClipComponent.cs.meta ================================================ fileFormatVersion: 2 guid: 5f529b9d4c944447b01155db88a9110e MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Behaviour.meta ================================================ fileFormatVersion: 2 guid: 09335eee0c50433a9540e0834dc033e1 timeCreated: 1700728805 ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Event/ScriptableEventLocaleText.cs ================================================ using VirtueSky.Events; using VirtueSky.Inspector; namespace VirtueSky.Localization { using UnityEngine; [CreateAssetMenu(fileName = "event_localetext.asset", menuName = "Sunflower/Localization/Events/locale text")] [EditorIcon("scriptable_event")] public class ScriptableEventLocaleText : BaseEvent { } } ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Event/ScriptableEventLocaleText.cs.meta ================================================ fileFormatVersion: 2 guid: 0818b2a65300c6e4e9a33fe916a194c0 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Event.meta ================================================ fileFormatVersion: 2 guid: 13cc2fa7ae5daac4bbd5726c0c69486d folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Variable/LocaleAudioClip.cs ================================================ using System; using System.Linq; using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Localization { [CreateAssetMenu(menuName = "Sunflower/Localization/AudioClip", fileName = "audioclip_localizevalue", order = 7)] [EditorIcon("scriptable_yellow_audioclip")] public class LocaleAudioClip : LocaleVariable { [Serializable] private class AudioClipLocaleItem : LocaleItem { }; [SerializeField] private AudioClipLocaleItem[] items = new AudioClipLocaleItem[1]; // ReSharper disable once CoVariantArrayConversion public override LocaleItemBase[] LocaleItems => items; } } ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Variable/LocaleAudioClip.cs.meta ================================================ fileFormatVersion: 2 guid: b083367c44e04827abfa540062a41c21 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 2579f1f676b7f2843a4cafaf429f9474, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Variable/LocaleFont.cs ================================================ using System; using System.Linq; using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Localization { [CreateAssetMenu(menuName = "Sunflower/Localization/Font", fileName = "font_localizevalue", order = 1)] [EditorIcon("scriptable_yellow_font")] public class LocaleFont : LocaleVariable { [Serializable] private class FontLocaleItem : LocaleItem { }; [SerializeField] private FontLocaleItem[] items = new FontLocaleItem[1]; // ReSharper disable once CoVariantArrayConversion public override LocaleItemBase[] LocaleItems => items; } } ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Variable/LocaleFont.cs.meta ================================================ fileFormatVersion: 2 guid: 759309c703f44e55a8b2e699057b6670 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 6612c7be3408486478603096058345a2, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Variable/LocaleMaterial.cs ================================================ using System; using VirtueSky.Inspector; namespace VirtueSky.Localization { using UnityEngine; [CreateAssetMenu(menuName = "Sunflower/Localization/Material", fileName = "material_localizevalue", order = 1)] [EditorIcon("scriptable_yellow_material")] public class LocaleMaterial : LocaleVariable { [Serializable] private class MaterialLocaleItem : LocaleItem { }; [SerializeField] private MaterialLocaleItem[] items = new MaterialLocaleItem[1]; // ReSharper disable once CoVariantArrayConversion public override LocaleItemBase[] LocaleItems => items; } } ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Variable/LocaleMaterial.cs.meta ================================================ fileFormatVersion: 2 guid: acdfe7459f01ac840b0d9cf370ab27ab MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 0bf47bf639988dc499e672dd3d0b7c26, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Variable/LocalePrefab.cs ================================================ using System; using System.Linq; using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Localization { [CreateAssetMenu(menuName = "Sunflower/Localization/GameObject", fileName = "gameobject_localizevalue", order = 2)] [EditorIcon("scriptable_yellow_gameobject")] public class LocalePrefab : LocaleVariable { [Serializable] private class PrefabLocaleItem : LocaleItem { }; [SerializeField] private PrefabLocaleItem[] items = new PrefabLocaleItem[1]; // ReSharper disable once CoVariantArrayConversion public override LocaleItemBase[] LocaleItems => items; } } ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Variable/LocalePrefab.cs.meta ================================================ fileFormatVersion: 2 guid: 0196d594670d4bf787f969202971648d MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: bfd31c3e578dee04295c2133a97be5dd, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Variable/LocaleSprite.cs ================================================ using System; using System.Linq; using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Localization { [CreateAssetMenu(menuName = "Sunflower/Localization/Sprite", fileName = "sprite_localizevalue", order = 3)] [EditorIcon("scriptable_yellow_sprite")] public class LocaleSprite : LocaleVariable { [Serializable] private class SpriteLocaleItem : LocaleItem { }; [SerializeField] private SpriteLocaleItem[] items = new SpriteLocaleItem[1]; // ReSharper disable once CoVariantArrayConversion public override LocaleItemBase[] LocaleItems => items.ToArray(); } } ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Variable/LocaleSprite.cs.meta ================================================ fileFormatVersion: 2 guid: 3481dbc1ff9b4f4eac1a0eae04e50bf4 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: b2b3b70f4d3c0884faa424282862c6ca, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Variable/LocaleTMPFont.cs ================================================ using System; using TMPro; using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Localization { [CreateAssetMenu(menuName = "Sunflower/Localization/TMPFont", fileName = "font_asset_localizevalue", order = 1)] [EditorIcon("scriptable_yellow_fontasset")] public class LocaleTMPFont : LocaleVariable { [Serializable] private class TMPFontLocaleItem : LocaleItem { }; [SerializeField] private TMPFontLocaleItem[] items = new TMPFontLocaleItem[1]; // ReSharper disable once CoVariantArrayConversion public override LocaleItemBase[] LocaleItems => items; } } ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Variable/LocaleTMPFont.cs.meta ================================================ fileFormatVersion: 2 guid: 2400eef271b142798c5180db7f2084e6 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 120a98534767efd4ba0b7a9e91cda393, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Variable/LocaleText.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using UnityEngine; using VirtueSky.Inspector; using VirtueSky.Linq; namespace VirtueSky.Localization { [CreateAssetMenu(menuName = "Sunflower/Localization/Text", fileName = "text_localizevalue", order = 4)] [EditorIcon("scriptable_yellow_text")] [Serializable] public class LocaleText : LocaleVariable { [Serializable] private class TextLocaleItem : LocaleItem { }; [SerializeField] private TextLocaleItem[] items = new TextLocaleItem[1]; // ReSharper disable once CoVariantArrayConversion public override LocaleItemBase[] LocaleItems => items; /// /// Sets locale items in Editor or Playmode. /// public void SetLocaleItems(List> items) { if (items == null) throw new ArgumentNullException(nameof(items)); this.items = items.Map(i => new TextLocaleItem { Language = i.Language, Value = i.Value }).ToArray(); } /// /// Sets locale items in Editor or Playmode. /// public void SetLocaleItems(LocaleItem[] items) { if (items == null) throw new ArgumentException(nameof(items)); this.items = items.Map(i => new TextLocaleItem { Language = i.Language, Value = i.Value }).ToArray(); } } } ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Variable/LocaleText.cs.meta ================================================ fileFormatVersion: 2 guid: 23c351e45916415fa870992171e2731d MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 13605300fcfb1fd45b49212af32ba2f8, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Variable/LocaleTextAsset.cs ================================================ using System; using System.Linq; using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Localization { [CreateAssetMenu(menuName = "Sunflower/Localization/TextAsset", fileName = "textasset_localizevalue", order = 5)] [EditorIcon("scriptable_yellow_textasset")] public class LocaleTextAsset : LocaleVariable { [Serializable] private class TextAssetLocaleItem : LocaleItem { }; [SerializeField] private TextAssetLocaleItem[] items = new TextAssetLocaleItem[1]; // ReSharper disable once CoVariantArrayConversion public override LocaleItemBase[] LocaleItems => items; } } ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Variable/LocaleTextAsset.cs.meta ================================================ fileFormatVersion: 2 guid: 7929c07a091e42b9bc29fb15a91900ae MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5b605beec23f2f6408ce4cae4dedd075, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Variable/LocaleTexture.cs ================================================ using System; using System.Linq; using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Localization { [CreateAssetMenu(menuName = "Sunflower/Localization/Texture", fileName = "texture_localizevalue", order = 6)] [EditorIcon("scriptable_yellow_texture")] public class LocaleTexture : LocaleVariable { [Serializable] private class TextureLocaleItem : LocaleItem { }; [SerializeField] private TextureLocaleItem[] items = new TextureLocaleItem[1]; // ReSharper disable once CoVariantArrayConversion public override LocaleItemBase[] LocaleItems => items; } } ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Variable/LocaleTexture.cs.meta ================================================ fileFormatVersion: 2 guid: c12f7ea24b48413fa8c5e43f78cf029a MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: a7f0847a6f95e2e46a76f375e4c2d001, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Variable/LocaleVariable.cs ================================================ using System; using System.Linq; using UnityEngine; namespace VirtueSky.Localization { [Serializable] public abstract class LocaleVariable : ScriptableLocaleBase where T : class { /// /// Gets the defined locale items of the localized asset with concrete type. /// public LocaleItem[] TypedLocaleItems => (LocaleItem[])LocaleItems; /// /// Gets localized asset value regarding to if available. /// Gets first value of the asset if application is not playing. /// /// public T Value { get { var value = default(T); var isValueSet = false; #if UNITY_EDITOR if (Application.isPlaying) { #endif isValueSet = TryGetLocaleValue(Locale.CurrentLanguage, out value); #if UNITY_EDITOR } else { // Get default language from settings if is not in Play mode. if (LocaleSettings.AvailableLanguages.Any()) { isValueSet = TryGetLocaleValue(LocaleSettings.AvailableLanguages.First(), out value); } } #endif return isValueSet ? value : FirstValue; } } /// /// Gets the first locale value of the asset. /// public T FirstValue { get { var localeItem = TypedLocaleItems.FirstOrDefault(); return localeItem?.Value; } } /// /// Returns the language given is whether exist or not. /// public bool HasLocale(Language language) { return LocaleItems.Any(x => x.Language == language); } /// /// Gets localized value if exist regarding to given language. /// /// True if exist; otherwise False public bool TryGetLocaleValue(Language language, out T value) { int index = Array.FindIndex(TypedLocaleItems, x => x.Language == language); if (index >= 0) { value = TypedLocaleItems[index].Value; return true; } value = default; return false; } /// /// Returns LocalizedAsset value. /// /// LocalizedAsset public static implicit operator T(LocaleVariable asset) { return asset ? asset.Value : default; } public override Type GetGenericType => typeof(T); } } ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Variable/LocaleVariable.cs.meta ================================================ fileFormatVersion: 2 guid: b7226a36e35142058fdda749745c14e3 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Variable/LocaleVideoClip.cs ================================================ using System; using System.Linq; using UnityEngine; using UnityEngine.Video; using VirtueSky.Inspector; namespace VirtueSky.Localization { [CreateAssetMenu(menuName = "Sunflower/Localization/VideoClip", fileName = "videoclip_localizevalue", order = 8)] [EditorIcon("scriptable_yellow_videoclip")] public class LocaleVideoClip : LocaleVariable { [Serializable] private class VideoClipLocaleItem : LocaleItem { }; [SerializeField] private VideoClipLocaleItem[] items = new VideoClipLocaleItem[1]; // ReSharper disable once CoVariantArrayConversion public override LocaleItemBase[] LocaleItems => items; } } ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Variable/LocaleVideoClip.cs.meta ================================================ fileFormatVersion: 2 guid: 00a0dc7355054137b8ab518f1fe0e443 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: a3d36db6a75640543bcec2d532f8498d, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Variable/ScriptableLocaleBase.cs ================================================ using System; using UnityEngine; namespace VirtueSky.Localization { [Serializable] public abstract class ScriptableLocaleBase : ScriptableObject { /// /// Gets the read-only locale items. /// public abstract LocaleItemBase[] LocaleItems { get; } /// /// Gets the value type. /// public abstract Type GetGenericType { get; } } } ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Variable/ScriptableLocaleBase.cs.meta ================================================ fileFormatVersion: 2 guid: c1ae0dd6c1624e26bf027ad29c93dde1 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Localization/Runtime/Implement/Variable.meta ================================================ fileFormatVersion: 2 guid: 7d46e937b5184e84b34422baea51d6ab timeCreated: 1700728721 ================================================ FILE: VirtueSky/Localization/Runtime/Implement.meta ================================================ fileFormatVersion: 2 guid: 898d16718da54a7fa8ae5dab58e7a490 timeCreated: 1700728709 ================================================ FILE: VirtueSky/Localization/Runtime/Language.cs ================================================ using System; using UnityEngine; namespace VirtueSky.Localization { [Serializable] public class Language : IEquatable { public static Language[] BuiltInLanguages { get { return new[] { Afrikaans, Arabic, Basque, Belarusian, Bulgarian, Catalan, Chinese, Czech, Danish, Dutch, English, Estonian, Faroese, Finnish, French, German, Greek, Hebrew, Hungarian, Icelandic, Indonesian, Italian, Japanese, Korean, Latvian, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian, SerboCroatian, Slovak, Slovenian, Spanish, Swedish, Thai, Turkish, Ukrainian, Vietnamese }; } } public static Language Afrikaans => new(SystemLanguage.Afrikaans.ToString(), "af"); public static Language Arabic => new(SystemLanguage.Arabic.ToString(), "ar"); public static Language Basque => new(SystemLanguage.Basque.ToString(), "eu"); public static Language Belarusian => new(SystemLanguage.Belarusian.ToString(), "be"); public static Language Bulgarian => new(SystemLanguage.Bulgarian.ToString(), "bg"); public static Language Catalan => new(SystemLanguage.Catalan.ToString(), "ca"); public static Language Chinese => new(SystemLanguage.Chinese.ToString(), "zh"); public static Language Czech => new(SystemLanguage.Czech.ToString(), "cs"); public static Language Danish => new(SystemLanguage.Danish.ToString(), "da"); public static Language Dutch => new(SystemLanguage.Dutch.ToString(), "nl"); public static Language English => new(SystemLanguage.English.ToString(), "en"); public static Language Estonian => new(SystemLanguage.Estonian.ToString(), "et"); public static Language Faroese => new(SystemLanguage.Faroese.ToString(), "fo"); public static Language Finnish => new(SystemLanguage.Finnish.ToString(), "fi"); public static Language French => new(SystemLanguage.French.ToString(), "fr"); public static Language German => new(SystemLanguage.German.ToString(), "de"); public static Language Greek => new(SystemLanguage.Greek.ToString(), "el"); public static Language Hebrew => new(SystemLanguage.Hebrew.ToString(), "he"); public static Language Hungarian => new(SystemLanguage.Hungarian.ToString(), "hu"); public static Language Icelandic => new(SystemLanguage.Icelandic.ToString(), "is"); public static Language Indonesian => new(SystemLanguage.Indonesian.ToString(), "id"); public static Language Italian => new(SystemLanguage.Italian.ToString(), "it"); public static Language Japanese => new(SystemLanguage.Japanese.ToString(), "ja"); public static Language Korean => new(SystemLanguage.Korean.ToString(), "ko"); public static Language Latvian => new(SystemLanguage.Latvian.ToString(), "lv"); public static Language Lithuanian => new(SystemLanguage.Lithuanian.ToString(), "lt"); public static Language Norwegian => new(SystemLanguage.Norwegian.ToString(), "no"); public static Language Polish => new(SystemLanguage.Polish.ToString(), "pl"); public static Language Portuguese => new(SystemLanguage.Portuguese.ToString(), "pt"); public static Language Romanian => new(SystemLanguage.Romanian.ToString(), "ro"); public static Language Russian => new(SystemLanguage.Russian.ToString(), "ru"); public static Language SerboCroatian => new(SystemLanguage.SerboCroatian.ToString(), "hr"); public static Language Slovak => new(SystemLanguage.Slovak.ToString(), "sk"); public static Language Slovenian => new(SystemLanguage.Slovenian.ToString(), "sl"); public static Language Spanish => new(SystemLanguage.Spanish.ToString(), "es"); public static Language Swedish => new(SystemLanguage.Swedish.ToString(), "sv"); public static Language Thai => new(SystemLanguage.Thai.ToString(), "th"); public static Language Turkish => new(SystemLanguage.Turkish.ToString(), "tr"); public static Language Ukrainian => new(SystemLanguage.Ukrainian.ToString(), "uk"); public static Language Vietnamese => new(SystemLanguage.Vietnamese.ToString(), "vi"); [SerializeField] private string name; [SerializeField] private string code; [SerializeField] private bool custom; public string Name => name; public string Code => code; public bool Custom => custom; public Language(string name, string code, bool custom = false) { this.name = name ?? ""; this.code = code ?? ""; this.custom = custom; } public bool Equals(Language other) { if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; return Code == other.Code; } public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; if (obj.GetType() != this.GetType()) return false; return Equals((Language)obj); } public override int GetHashCode() { return Code.GetHashCode(); } public static bool operator ==(Language left, Language right) { return Equals(left, right); } public static bool operator !=(Language left, Language right) { return !Equals(left, right); } public override string ToString() { return Name; } public static implicit operator Language(SystemLanguage systemLanguage) { int index = Array.FindIndex(BuiltInLanguages, x => x.name == systemLanguage.ToString()); return index >= 0 ? BuiltInLanguages[index] : English; } public static explicit operator SystemLanguage(Language language) { if (language.custom) return SystemLanguage.Unknown; var systemLanguages = (SystemLanguage[])Enum.GetValues(typeof(SystemLanguage)); int index = Array.FindIndex(systemLanguages, x => x.ToString() == language.Name); return index >= 0 ? systemLanguages[index] : SystemLanguage.Unknown; } } } ================================================ FILE: VirtueSky/Localization/Runtime/Language.cs.meta ================================================ fileFormatVersion: 2 guid: f4c852d065584f4fa9b0a18d3c64bad8 timeCreated: 1700644636 ================================================ FILE: VirtueSky/Localization/Runtime/Locale.cs ================================================ using System; using System.Linq; using UnityEngine; using VirtueSky.DataStorage; namespace VirtueSky.Localization { public sealed class Locale { private static Locale instance; private Language _currentLanguage = Language.English; /// /// Raised when has been changed. /// private event EventHandler OnLocaleChangedEvent; private static Locale Instance { get { #if UNITY_EDITOR if (!Application.isPlaying) { Debug.LogError("Locale only avaiable when application playing!"); return null; } #endif if (instance == null) { instance = new Locale(); instance.SetDefaultLanguage(); } return instance; } } public static Language CurrentLanguage { get => Instance._currentLanguage; set { if (Instance._currentLanguage != value) { Instance._currentLanguage = value; SetCurrentLanguageCode(value); var oldValue = Instance._currentLanguage; Instance._currentLanguage = value; Instance.OnLanguageChanged(new LocaleChangedEventArgs(oldValue, value)); } } } public static EventHandler LocaleChangedEvent { get => Instance.OnLocaleChangedEvent; set => Instance.OnLocaleChangedEvent = value; } private void OnLanguageChanged(LocaleChangedEventArgs e) { OnLocaleChangedEvent?.Invoke(this, e); } /// /// Sets the as . /// public void SetSystemLanguage() { CurrentLanguage = Application.systemLanguage; } /// /// Sets the to default language defined in . /// public void SetDefaultLanguage() { CurrentLanguage = LocaleSettings.AvailableLanguages.FirstOrDefault(); } /// /// Finds all localized assets with type given. Finds all assets in the project if in Editor; otherwise, /// finds only that loaded in memory. /// /// Array of specified localized assets. public static T[] FindAllLocalizedAssets() where T : ScriptableLocaleBase { #if UNITY_EDITOR string[] guids = UnityEditor.AssetDatabase.FindAssets($"t:{typeof(T)}"); var assets = new T[guids.Length]; for (var i = 0; i < guids.Length; ++i) { string assetPath = UnityEditor.AssetDatabase.GUIDToAssetPath(guids[i]); assets[i] = UnityEditor.AssetDatabase.LoadAssetAtPath(assetPath); Debug.Assert(assets[i]); } return assets; #else return Resources.FindObjectsOfTypeAll(); #endif } /// /// Finds all localized assets. /// /// /// Array of localized assets. public static ScriptableLocaleBase[] FindAllLocalizedAssets() { return FindAllLocalizedAssets(); } const string KEY_LANGUAGE = "KEY_LANGUAGE"; public static string GetCurrentLanguageCode() => GameData.Get(KEY_LANGUAGE, ""); public static void SetCurrentLanguageCode(Language language) => GameData.Set(KEY_LANGUAGE, language.Code); public static void SetCurrentLanguageCode(string languageCode) => GameData.Set(KEY_LANGUAGE, languageCode); public static void LoadLanguageSetting() { var list = LocaleSettings.AvailableLanguages; string lang = GetCurrentLanguageCode(); // for first time when user not choose lang to display // use system language, if you don't use detect system language use first language in list available laguages if (string.IsNullOrEmpty(lang)) { var index = 0; if (LocaleSettings.DetectDeviceLanguage) { var nameSystemLang = UnityEngine.Application.systemLanguage.ToString(); index = list.FindIndex(x => x.Name == nameSystemLang); if (index < 0) index = 0; } lang = list[index].Code; SetCurrentLanguageCode(lang); } int i = list.FindIndex(x => x.Code == lang); Locale.CurrentLanguage = list[i]; } } } ================================================ FILE: VirtueSky/Localization/Runtime/Locale.cs.meta ================================================ fileFormatVersion: 2 guid: a71f9cb605674f52bb2028bbb37a4672 timeCreated: 1700707788 ================================================ FILE: VirtueSky/Localization/Runtime/LocaleChangedEventArgs.cs ================================================ using System; namespace VirtueSky.Localization { public class LocaleChangedEventArgs : EventArgs { public LocaleChangedEventArgs(Language previous, Language current) { Previous = previous; Current = current; } public Language Previous { get; private set; } public Language Current { get; private set; } } } ================================================ FILE: VirtueSky/Localization/Runtime/LocaleChangedEventArgs.cs.meta ================================================ fileFormatVersion: 2 guid: e485a91b41894d0da5e125509c7a1afc timeCreated: 1700721928 ================================================ FILE: VirtueSky/Localization/Runtime/LocaleItem.cs ================================================ using System; using UnityEngine; namespace VirtueSky.Localization { [Serializable] public class LocaleItem : LocaleItemBase { [SerializeField] private T value; public T Value { get => value; set => this.value = value; } public override object ObjectValue { get => value; set => this.value = (T)value; } public LocaleItem() { } public LocaleItem(Language language, T value) { Language = language; Value = value; } } } ================================================ FILE: VirtueSky/Localization/Runtime/LocaleItem.cs.meta ================================================ fileFormatVersion: 2 guid: 4756bcf8dc22492fb771f98af7db141b timeCreated: 1700705854 ================================================ FILE: VirtueSky/Localization/Runtime/LocaleItemBase.cs ================================================ using System; using UnityEngine; namespace VirtueSky.Localization { [Serializable] public abstract class LocaleItemBase { [SerializeField] private Language language = Language.English; public Language Language { get => language; set => language = value; } public abstract object ObjectValue { get; set; } } } ================================================ FILE: VirtueSky/Localization/Runtime/LocaleItemBase.cs.meta ================================================ fileFormatVersion: 2 guid: 3b558057d4e74740a2d510f527cf894b timeCreated: 1700705405 ================================================ FILE: VirtueSky/Localization/Runtime/LocaleSettings.cs ================================================ using System.Collections.Generic; using System.Linq; using UnityEngine; using VirtueSky.Inspector; using VirtueSky.Linq; using VirtueSky.Utils; namespace VirtueSky.Localization { [EditorIcon("icon_scriptable")] public sealed class LocaleSettings : ScriptableSettings { [SerializeField] private List availableLanguages = new(1) { Language.English }; [SerializeField] private bool detectDeviceLanguage; [SerializeField] private string importLocation = "Assets/_Sunflower/Scriptable/Localization"; [SerializeField] private string googleTranslateApiKey; [SerializeField] private string spreadsheetKey; [SerializeField, TextArea] private string serviceAccountCredential; public static bool DetectDeviceLanguage => Instance.detectDeviceLanguage; public static string ImportLocation => Instance.importLocation; public static List AvailableLanguages => Instance.availableLanguages; public static string GoogleTranslateApiKey => Instance.googleTranslateApiKey; public static string SpreadsheetKey => Instance.spreadsheetKey; public static string ServiceAccountCredential => Instance.serviceAccountCredential; public static List AllLanguages { get { var languages = new List(); languages.AddRange(Language.BuiltInLanguages); languages.AddRange(AvailableLanguages.Filter(l => l.Custom)); return languages; } } } } ================================================ FILE: VirtueSky/Localization/Runtime/LocaleSettings.cs.meta ================================================ fileFormatVersion: 2 guid: f4d69dc1bc6643cb8580d1dd9e553e92 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: ed5ec0bb4ec55df47af0ecc2bd7be5f9, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Localization/Runtime/Translate/GoogleTranslateRequest.cs ================================================ using System; namespace VirtueSky.Localization { [Serializable] public class GoogleTranslateRequest { public Language source; public Language target; public string value; public GoogleTranslateRequest() { } public GoogleTranslateRequest(Language source, Language target, string value) { this.source = source; this.target = target; this.value = value; } } } ================================================ FILE: VirtueSky/Localization/Runtime/Translate/GoogleTranslateRequest.cs.meta ================================================ fileFormatVersion: 2 guid: d1ee312ff8d9b8c41aa5182095361b3a MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Localization/Runtime/Translate/GoogleTranslateResponse.cs ================================================ using System; namespace VirtueSky.Localization { [Serializable] public class GoogleTranslateResponse { public string translatedText; public string detectedSourceLanguage; public GoogleTranslateResponse() { } public GoogleTranslateResponse(string translatedText) { this.translatedText = translatedText; } } } ================================================ FILE: VirtueSky/Localization/Runtime/Translate/GoogleTranslateResponse.cs.meta ================================================ fileFormatVersion: 2 guid: 017db063730c427aa1deeb09d59f690c timeCreated: 1701241276 ================================================ FILE: VirtueSky/Localization/Runtime/Translate/GoogleTranslator.cs ================================================ using System; using System.Collections; using UnityEngine; using UnityEngine.Networking; namespace VirtueSky.Localization { public sealed class GoogleTranslator { private const string REQUEST_URL_V2 = "https://translation.googleapis.com/language/translate/v2?key={0}"; private const string REQUEST_KEY_INPUT_TEXT = "q"; private const string REQUEST_KEY_SOURCE_LANGUAGE = "source"; private const string REQUEST_KEY_TARGET_LANGUAGE = "target"; /// /// Gets or sets the google cloud API key. /// /// public string AuthCredential { get; set; } public GoogleTranslator(string authCredential) { AuthCredential = authCredential; } /// /// Performs translation with given translate request asynchronous. /// /// Translate request. /// Completed action. /// Error action. public IEnumerator TranslateAsync( GoogleTranslateRequest request, Action onCompleted = null, Action onError = null) { using (var www = PrepareRequest(request)) { #if UNITY_2017_2_OR_NEWER yield return www.SendWebRequest(); #else yield return www.Send(); #endif ProcessResponse(request, www, onCompleted, onError); } } /// /// Useful for Editor scripts. Otherwise, recommended to use . /// /// Translate request. /// Completed action. /// Error action. public void Translate(GoogleTranslateRequest request, Action onCompleted = null, Action onError = null) { using (var www = PrepareRequest(request)) { #if UNITY_2017_2_OR_NEWER www.SendWebRequest(); #else www.Send(); #endif // Wait request completion. while (!www.isDone) { } ProcessResponse(request, www, onCompleted, onError); } } private UnityWebRequest PrepareRequest(GoogleTranslateRequest request) { if (request == null) throw new ArgumentNullException(nameof(request)); if (string.IsNullOrEmpty(AuthCredential)) { // ReSharper disable once NotResolvedInText throw new ArgumentNullException("AuthCredential", "Auth credential missing!"); } var form = new WWWForm(); form.AddField(REQUEST_KEY_INPUT_TEXT, request.value); form.AddField(REQUEST_KEY_SOURCE_LANGUAGE, request.source.Code); form.AddField(REQUEST_KEY_TARGET_LANGUAGE, request.target.Code); var url = string.Format(REQUEST_URL_V2, AuthCredential); return UnityWebRequest.Post(url, form); } private void ProcessResponse( GoogleTranslateRequest request, UnityWebRequest www, Action onCompleted, Action onError) { if (www.result is UnityWebRequest.Result.ConnectionError or UnityWebRequest.Result.ProtocolError) { onError?.Invoke(new TranslationErrorEventArgs(www.error, www.responseCode)); } else { var response = JsonUtility.FromJson(www.downloadHandler.text); if (response is { data: { translations: { Length: > 0 } } }) { var requests = new[] { request }; var translateResponse = new GoogleTranslateResponse { translatedText = response.data.translations[0].translatedText }; var responses = new[] { translateResponse }; onCompleted?.Invoke(new TranslationCompletedEventArgs(requests, responses)); } else { if (response != null && response.error != null) { onError?.Invoke(new TranslationErrorEventArgs(response.error.message, response.error.code)); } onError?.Invoke(new TranslationErrorEventArgs("Response data could not be read.", -1)); } } } [Serializable] private class JsonResponse { public JsonData data = null; public JsonError error = null; } [Serializable] private class JsonData { public JsonTranslation[] translations = null; } [Serializable] private class JsonError { public int code = 0; public string message = null; } [Serializable] private class JsonTranslation { public string translatedText = ""; public string detectedSourceLanguage = ""; } } /// /// Provides the requests and translation responses. /// public class TranslationCompletedEventArgs : EventArgs { /// /// Translate requests. /// public GoogleTranslateRequest[] Requests { get; private set; } /// /// Translate responses. /// public GoogleTranslateResponse[] Responses { get; private set; } public TranslationCompletedEventArgs(GoogleTranslateRequest[] requests, GoogleTranslateResponse[] responses) { Debug.Assert(requests != null); Debug.Assert(responses != null); Requests = requests; Responses = responses; } } /// /// Provides detailed information upon translation errors. /// public class TranslationErrorEventArgs : EventArgs { /// /// Error code. /// public long ResponseCode { get; private set; } /// /// Error message. /// public string Message { get; private set; } public TranslationErrorEventArgs(string message, long responseCode) { ResponseCode = responseCode; Message = message; } } } ================================================ FILE: VirtueSky/Localization/Runtime/Translate/GoogleTranslator.cs.meta ================================================ fileFormatVersion: 2 guid: 421898eccc5b4bd8800940b882b63994 timeCreated: 1701241382 ================================================ FILE: VirtueSky/Localization/Runtime/Translate.meta ================================================ fileFormatVersion: 2 guid: 241b88041d83c1d42a2be9d6d6bc2fc4 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Localization/Runtime/VirtueSky.Sunflower.Localization.asmdef ================================================ { "name": "VirtueSky.Sunflower.Localization", "rootNamespace": "", "references": [ "GUID:efdee36e63e4ce34a91071531ec746c1", "GUID:6055be8ebefd69e48b49212b09b47b2f", "GUID:324caed91501a9c47a04ebfd87b68794", "GUID:bd40169efe8642149b1d2b72ba4903ce", "GUID:acb3cac55c622ec459c8caadf707623a", "GUID:c282fd4f3fc2c7540914e85842a013c7", "GUID:fca7ec166e04dc948b624a983315e2c9", "GUID:32dbaa332e571bf429b7de517f75f074" ], "includePlatforms": [], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], "versionDefines": [], "noEngineReferences": false } ================================================ FILE: VirtueSky/Localization/Runtime/VirtueSky.Sunflower.Localization.asmdef.meta ================================================ fileFormatVersion: 2 guid: c7e7793e0b5d326429f90e6fd716775e AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Localization/Runtime.meta ================================================ fileFormatVersion: 2 guid: 398dc987f9c00a140bf71180081694b0 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Localization.meta ================================================ fileFormatVersion: 2 guid: 4e2227bb265fbe64bab7f2d4a5c08a8e folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Misc/Common.Animancer.cs ================================================ using System; #if VIRTUESKY_ANIMANCER using Animancer; namespace VirtueSky.Misc { public static partial class Common { public static AnimancerComponent PlayClip(this AnimancerComponent animancerComponent, ClipTransition clip, Action _endAnim = null, float _durationFade = .2f, bool isCheckPlayingClip = true, FadeMode mode = default, object _owner = null) { if (isCheckPlayingClip) { if (!animancerComponent.IsPlaying(clip)) { Handle(); } } else { Handle(); } void Handle() { var state = animancerComponent.Play(clip, clip.Clip.length * _durationFade, mode); if (_endAnim != null) { object owner = _owner ?? animancerComponent; state.Events(owner).OnEnd += OnEndAnim; void OnEndAnim() { state.Events(owner).OnEnd -= OnEndAnim; _endAnim?.Invoke(); } } } return animancerComponent; } // Freeze a single animation on its current frame: public static AnimancerComponent PauseClip(this AnimancerComponent animancerComponent, ClipTransition clip) { animancerComponent.States[clip].IsPlaying = false; return animancerComponent; } // Freeze all animations on their current frame: public static AnimancerComponent PauseAll(this AnimancerComponent animancerComponent) { animancerComponent.Graph.PauseGraph(); return animancerComponent; } // Stop a single animation from affecting the character and rewind it to the start: public static AnimancerComponent StopClip(this AnimancerComponent animancerComponent, ClipTransition clip) { animancerComponent.Stop(clip); // Or you can call it on the state directly: var state = animancerComponent.States[clip]; state.Stop(); return animancerComponent; } // Stop all animations from affecting the character and rewind them to the start: public static AnimancerComponent StopAll(this AnimancerComponent animancerComponent) { animancerComponent.Stop(); return animancerComponent; } } } #endif ================================================ FILE: VirtueSky/Misc/Common.Animancer.cs.meta ================================================ fileFormatVersion: 2 guid: 7ecabf26c8cd44aeb094d2342c0e2d47 timeCreated: 1708072435 ================================================ FILE: VirtueSky/Misc/Common.Collections.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; namespace VirtueSky.Misc { public partial class Common { public static void Clear(this T[] collection) { if (collection == null) throw new ArgumentNullException(nameof(collection)); Array.Clear(collection, 0, collection.Length); } #region IsNullOrEmpty [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNullOrEmpty(this List source) { return source == null || source.Count == 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNullOrEmpty(this T[] source) { return source == null || source.Length == 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNullOrEmpty(this Dictionary source) { return source == null || source.Keys.Count == 0; } #endregion #region Shuffle [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Shuffle(this T[] source) { int n = source.Length; while (n > 1) { n--; int k = UnityEngine.Random.Range(0, n); (source[k], source[n]) = (source[n], source[k]); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Shuffle(this List source) { int n = source.Count; while (n > 1) { n--; int k = UnityEngine.Random.Range(0, n); (source[k], source[n]) = (source[n], source[k]); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static IDictionary Shuffle(this IDictionary source) { var keys = source.Keys.ToArray(); var values = source.Values.ToArray(); int n = source.Count; while (n > 1) { n--; int k = UnityEngine.Random.Range(0, n); (keys[k], keys[n]) = (keys[n], keys[k]); (values[k], values[n]) = (values[n], values[k]); } return MakeDictionary(keys, values); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static IDictionary MakeDictionary(this TKey[] keys, TValue[] values) { if (keys == null) throw new ArgumentNullException(nameof(keys)); if (values == null) throw new ArgumentNullException(nameof(values)); if (keys.Length != values.Length) throw new ArgumentException("Size keys and size values diffirent!"); IDictionary result = new Dictionary(); for (var i = 0; i < keys.Length; i++) { result.Add(keys[i], values[i]); } return result; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static IDictionary MakeDictionary(this IList keys, IList values) { if (keys == null) throw new ArgumentNullException(nameof(keys)); if (values == null) throw new ArgumentNullException(nameof(values)); if (keys.Count != values.Count) throw new ArgumentException("Size keys and size values diffirent!"); IDictionary result = new Dictionary(); for (var i = 0; i < keys.Count; i++) { result.Add(keys[i], values[i]); } return result; } #endregion #region Pick random [MethodImpl(MethodImplOptions.AggressiveInlining)] public static T PickRandom(this T[] collection) { if (collection == null) throw new ArgumentNullException(nameof(collection)); return collection.Length == 0 ? default : collection[UnityEngine.Random.Range(0, collection.Length)]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static T PickRandom(this List collection) { if (collection == null) throw new ArgumentNullException(nameof(collection)); return collection.Count == 0 ? default : collection[UnityEngine.Random.Range(0, collection.Count)]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static (T, int) PickRandomAndIndex(this T[] collection) { if (collection == null) throw new ArgumentNullException(nameof(collection)); int index = UnityEngine.Random.Range(0, collection.Length); return collection.Length == 0 ? (default, -1) : (collection[index], index); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static (T, int) PickRandomWithIndex(this List collection) { if (collection == null) throw new ArgumentNullException(nameof(collection)); var index = UnityEngine.Random.Range(0, collection.Count); return collection.Count == 0 ? (default, -1) : (collection[index], index); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static List PickRandomSubList(this List collection, int length) { if (collection == null) throw new ArgumentNullException(nameof(collection)); var listTemp = collection.ToList(); List pickList = new List(); listTemp.Shuffle(); for (int i = 0; i < listTemp.Count; i++) { if (i < length) pickList.Add(listTemp[i]); } return pickList; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static T[] PickRandomSubArray(this T[] collection, int length) { if (collection == null) throw new ArgumentNullException(nameof(collection)); T[] arrayTemp = new T[collection.Length]; Array.Copy(collection, arrayTemp, collection.Length); T[] pickArray = new T[length <= collection.Length ? length : collection.Length]; arrayTemp.Shuffle(); for (int i = 0; i < arrayTemp.Length; i++) { if (i < length) pickArray[i] = arrayTemp[i]; } return pickArray; } #endregion [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Swap(this T[] source, int oldIndex, int newIndex) { if (oldIndex < 0 || newIndex < 0 || oldIndex > source.Length || newIndex > source.Length) { #if UNITY_EDITOR UnityEngine.Debug.LogError("Index out of range!"); #endif return; } if (oldIndex == newIndex) return; (source[oldIndex], source[newIndex]) = (source[newIndex], source[oldIndex]); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Swap(this List source, int oldIndex, int newIndex) { if (oldIndex < 0 || newIndex < 0 || oldIndex > source.Count || newIndex > source.Count) { #if UNITY_EDITOR UnityEngine.Debug.LogError("Index out of range!"); #endif return; } if (oldIndex == newIndex) return; (source[oldIndex], source[newIndex]) = (source[newIndex], source[oldIndex]); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static T[] ForEach(this T[] source, Action action) { for (int i = source.Length - 1; i >= 0; i--) { action(source[i]); } return source; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static List ForEach(this List source, Action action) { for (int i = source.Count - 1; i >= 0; i--) { action(source[i]); } return source; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static T[] ForEach(this T[] source, Action action) { for (int i = source.Length - 1; i >= 0; i--) { action(source[i], i); } return source; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static List ForEach(this List source, Action action) { for (int i = source.Count - 1; i >= 0; i--) { action(source[i], i); } return source; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Removes(this List source, List entries) { for (var i = 0; i < entries.Count; i++) { source.Remove(entries[i]); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Removes(this List source, T[] entries) { foreach (var item in entries) { source.Remove(item); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static List Adds(this List source, List entries) { for (int i = 0; i < entries.Count; i++) { source.Add(entries[i]); } return source; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static List Adds(this List source, T[] entries) { foreach (var e in entries) { source.Add(e); } return source; } } } ================================================ FILE: VirtueSky/Misc/Common.Collections.cs.meta ================================================ fileFormatVersion: 2 guid: 17e2f19420454242aa4a49fa031c7c95 timeCreated: 1743264883 ================================================ FILE: VirtueSky/Misc/Common.Colors.cs ================================================ using System.Runtime.CompilerServices; using UnityEngine; using UnityEngine.UI; namespace VirtueSky.Misc { public partial class Common { public static Color SetAlpha(this Color color, float a) { color.a = a; return color; } public static Color SetRelativeAlpha(this Color color, float a) { color.a += a; return color; } public static Color SetRed(this Color color, float r) { color.r = r; return color; } public static Color SetRelativeRed(this Color color, float r) { color.r += r; return color; } public static Color SetGreen(this Color color, float g) { color.g = g; return color; } public static Color SetRelativeGreen(this Color color, float g) { color.g += g; return color; } public static Color SetBlue(this Color color, float b) { color.b = b; return color; } public static Color SetRelativeBlue(this Color color, float b) { color.b += b; return color; } public static Graphic SetAlpha(this Graphic graphic, float a) { var colorCache = graphic.color; colorCache.a = a; graphic.color = colorCache; return graphic; } public static Graphic SetRelativeAlpha(this Graphic graphic, float a) { var colorCache = graphic.color; colorCache.a += a; graphic.color = colorCache; return graphic; } public static Graphic SetRed(this Graphic graphic, float r) { var colorCache = graphic.color; colorCache.r = r; graphic.color = colorCache; return graphic; } public static Graphic SetRelativeRed(this Graphic graphic, float r) { var colorCache = graphic.color; colorCache.r += r; graphic.color = colorCache; return graphic; } public static Graphic SetGreen(this Graphic graphic, float g) { var colorCache = graphic.color; colorCache.g = g; graphic.color = colorCache; return graphic; } public static Graphic SetRelativeGreen(this Graphic graphic, float g) { var colorCache = graphic.color; colorCache.g += g; graphic.color = colorCache; return graphic; } public static Graphic SetBlue(this Graphic graphic, float b) { var colorCache = graphic.color; colorCache.b = b; graphic.color = colorCache; return graphic; } public static Graphic SetRelativeBlue(this Graphic graphic, float b) { var colorCache = graphic.color; colorCache.b += b; graphic.color = colorCache; return graphic; } public static SpriteRenderer SetAlpha(this SpriteRenderer renderer, float a) { var colorCache = renderer.color; colorCache.a = a; renderer.color = colorCache; return renderer; } public static SpriteRenderer SetRelativeAlpha(this SpriteRenderer renderer, float a) { var colorCache = renderer.color; colorCache.a += a; renderer.color = colorCache; return renderer; } public static SpriteRenderer SetRed(this SpriteRenderer renderer, float r) { var colorCache = renderer.color; colorCache.r = r; renderer.color = colorCache; return renderer; } public static SpriteRenderer SetRelativeRed(this SpriteRenderer renderer, float r) { var colorCache = renderer.color; colorCache.r += r; renderer.color = colorCache; return renderer; } public static SpriteRenderer SetGreen(this SpriteRenderer renderer, float g) { var colorCache = renderer.color; colorCache.g = g; renderer.color = colorCache; return renderer; } public static SpriteRenderer SetRelativeGreen(this SpriteRenderer renderer, float g) { var colorCache = renderer.color; colorCache.g += g; renderer.color = colorCache; return renderer; } public static SpriteRenderer SetBlue(this SpriteRenderer renderer, float b) { var colorCache = renderer.color; colorCache.b = b; renderer.color = colorCache; return renderer; } public static SpriteRenderer SetRelativeBlue(this SpriteRenderer renderer, float b) { var colorCache = renderer.color; colorCache.b += b; renderer.color = colorCache; return renderer; } /// /// Returns the color as a hexadecimal string in the format "#RRGGBB". /// /// The color to be converted. /// /// Hexadecimal string representing the color. /// public static string ToHtmlStringRGB(this Color color) { var color32 = new Color32((byte)Mathf.Clamp(Mathf.RoundToInt(color.r * byte.MaxValue), 0, byte.MaxValue), (byte)Mathf.Clamp(Mathf.RoundToInt(color.g * byte.MaxValue), 0, byte.MaxValue), (byte)Mathf.Clamp(Mathf.RoundToInt(color.b * byte.MaxValue), 0, byte.MaxValue), 1); return "#{0:X2}{1:X2}{2:X2}".Format(color32.r, color32.g, color32.b); } /// /// Returns the color as a hexadecimal string in the format "#RRGGBBAA". /// /// The color to be converted. /// /// Hexadecimal string representing the color. /// // ReSharper disable once InconsistentNaming public static string ToHtmlStringRGBA(this Color color) { var color32 = new Color32((byte)Mathf.Clamp(Mathf.RoundToInt(color.r * byte.MaxValue), 0, byte.MaxValue), (byte)Mathf.Clamp(Mathf.RoundToInt(color.g * byte.MaxValue), 0, byte.MaxValue), (byte)Mathf.Clamp(Mathf.RoundToInt(color.b * byte.MaxValue), 0, byte.MaxValue), (byte)Mathf.Clamp(Mathf.RoundToInt(color.a * byte.MaxValue), 0, byte.MaxValue)); return "#{0:X2}{1:X2}{2:X2}{3:X2}".Format(color32.r, color32.g, color32.b, color32.a); } public static bool TryParseHtmlString(this string htmlString, out Color color) { string stringColor = htmlString; if (!stringColor[0].Equals('#')) stringColor = stringColor.Insert(0, "#"); return ColorUtility.TryParseHtmlString(stringColor, out color); } } } ================================================ FILE: VirtueSky/Misc/Common.Colors.cs.meta ================================================ fileFormatVersion: 2 guid: 9a7d161837414c7d926cabd0ae959477 timeCreated: 1712478827 ================================================ FILE: VirtueSky/Misc/Common.Math.cs ================================================ using System.Runtime.CompilerServices; using UnityEngine; namespace VirtueSky.Misc { public partial class Common { #region Constants /// The circle constant. Defined as the circumference of a circle divided by its radius. Equivalent to 2*pi public const float TWO_PI = 6.28318530717959f; /// An obscure circle constant. Defined as the circumference of a circle divided by its diameter. Equivalent to 0.5*tau public const float PI = 3.14159265358979f; // PI / 2 OR 90 deg public const float PI_2 = 1.5707963267949f; // PI / 3 OR 60 deg public const float PI_3 = 1.04719755119659666667f; // PI / 4 OR 45 deg public const float PI_4 = 0.785398163397448f; // PI / 8 OR 22.5 deg public const float PI_8 = 0.392699081698724f; // PI / 16 OR 11.25 deg public const float PI_16 = 0.196349540849362f; // 3 * PI_2 OR 270 deg public const float THREE_PI_2 = 4.71238898038469f; /// Euler's number. The base of the natural logarithm. f(x)=e^x is equal to its own derivative public const float E = 2.71828182845905f; /// 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 public const float GOLDEN_RATIO = 1.61803398875f; /// The square root of two. The length of the vector (1,1) public const float SQRT2 = 1.4142135623731f; /// The reciprocal of the square root of two. The components of the vector (1,1) public const float RSQRT2 = 1f / SQRT2; /// Multiply an angle in degrees by this, to convert it to radians (2pi/360) public const float DEG_TO_RAD = 0.0174532925199433f; /// Multiply an angle in radians by this, to convert it to degrees (360/2pi) public const float RAD_TO_DEG = 57.2957795130823f; public const double DBL_EPSILON = 9.99999943962493E-11; #endregion #region Math operations /// Returns the square root of the given value [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Sqrt(this float value) => (float)System.Math.Sqrt(value); /// Returns the square root of each component [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Sqrt(this Vector2 v) => new Vector2(Sqrt(v.x), Sqrt(v.y)); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Sqrt(this Vector3 v) => new Vector3(Sqrt(v.x), Sqrt(v.y), Sqrt(v.z)); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 Sqrt(this Vector4 v) => new Vector4(Sqrt(v.x), Sqrt(v.y), Sqrt(v.z), Sqrt(v.w)); /// Returns value raised to the power of exponent [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Pow(this float value, float exponent) => (float)System.Math.Pow(value, exponent); /// Returns e to the power of the given value [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Exp(this float power) => (float)System.Math.Exp(power); /// Returns the logarithm of a value, with the given base [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Log(this float value, float @base) => (float)System.Math.Log(value, @base); /// Returns the natural logarithm of the given value [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Log(this float value) => (float)System.Math.Log(value); /// Returns the base 10 logarithm of the given value [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Log10(this float value) => (float)System.Math.Log10(value); #endregion #region Floating Point /// A very small value, used for various floating point inaccuracy thresholds public static readonly float Epsilon = UnityEngineInternal.MathfInternal.IsFlushToZeroEnabled ? UnityEngineInternal.MathfInternal.FloatMinNormal : UnityEngineInternal.MathfInternal.FloatMinDenormal; /// float.PositiveInfinity public const float Infinity = float.PositiveInfinity; /// float.NegativeInfinity public const float NegativeInfinity = float.NegativeInfinity; /// Returns whether or not two values are approximately equal. /// They are considered equal if they are within a M.Epsilon*8 or max(a,b)*0.000001f range of each other /// The first value to compare /// The second value to compare [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Approximately(this float a, float b) => Abs(b - a) < Max(0.000001f * Max(Abs(a), Abs(b)), Epsilon * 8); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Approximately(this Vector2 a, Vector2 b) => Approximately(a.x, b.x) && Approximately(a.y, b.y); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Approximately(this Vector3 a, Vector3 b) => Approximately(a.x, b.x) && Approximately(a.y, b.y) && Approximately(a.z, b.z); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Approximately(this Vector4 a, Vector4 b) => Approximately(a.x, b.x) && Approximately(a.y, b.y) && Approximately(a.z, b.z) && Approximately(a.w, b.w); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Approximately(this Color a, Color b) => Approximately(a.r, b.r) && Approximately(a.g, b.g) && Approximately(a.b, b.b) && Approximately(a.a, b.a); #endregion #region Trigonometry /// Returns the cosine of the given angle. Equivalent to the x-component of a unit vector with the same angle /// Angle in radians [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Cos(this float angRad) => (float)System.Math.Cos(angRad); /// Returns the sine of the given angle. Equivalent to the y-component of a unit vector with the same angle /// Angle in radians [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Sin(this float angRad) => (float)System.Math.Sin(angRad); /// Returns the tangent of the given angle /// Angle in radians [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Tan(this float angRad) => (float)System.Math.Tan(angRad); /// Returns the arc cosine of the given value, in radians /// A value between -1 and 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Acos(this float value) => (float)System.Math.Acos(value); /// Returns the arc sine of the given value, in radians /// A value between -1 and 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Asin(this float value) => (float)System.Math.Asin(value); /// Returns the arc tangent of the given value, in radians /// A value between -1 and 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Atan(this float value) => (float)System.Math.Atan(value); /// Returns the angle of a vector. I don't recommend using this function, it's confusing~ Use M.DirToAng instead /// The y component of the vector. They're flipped yeah I know but this is how everyone implements if for some godforsaken reason /// The x component of the vector. They're flipped yeah I know but this is how everyone implements if for some godforsaken reason [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Atan2(this float y, float x) => (float)System.Math.Atan2(y, x); /// Returns the cosecant of the given angle /// Angle in radians [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Csc(this float angRad) => 1f / (float)System.Math.Sin(angRad); /// Returns the secant of the given angle /// Angle in radians [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Sec(this float angRad) => 1f / (float)System.Math.Cos(angRad); /// Returns the cotangent of the given angle /// Angle in radians [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Cot(this float angRad) => 1f / (float)System.Math.Tan(angRad); /// Returns the versine of the given angle /// Angle in radians [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Ver(this float angRad) => 1 - (float)System.Math.Cos(angRad); /// Returns the coversine of the given angle /// Angle in radians [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Cvs(this float angRad) => 1 - (float)System.Math.Sin(angRad); /// Returns the chord of the given angle /// Angle in radians [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Crd(this float angRad) => 2 * (float)System.Math.Sin(angRad / 2); #endregion #region Hyperbolic Trigonometry /// Returns the hyperbolic cosine of the given hyperbolic angle [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Cosh(this float x) => (float)System.Math.Cosh(x); /// Returns the hyperbolic sine of the given hyperbolic angle [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Sinh(this float x) => (float)System.Math.Sinh(x); /// Returns the hyperbolic tangent of the given hyperbolic angle [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Tanh(this float x) => (float)System.Math.Tanh(x); /// Returns the hyperbolic arc cosine of the given value [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Acosh(this float x) => (float)System.Math.Log(x + Mathf.Sqrt(x * x - 1)); /// Returns the hyperbolic arc sine of the given value [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Asinh(this float x) => (float)System.Math.Log(x + Mathf.Sqrt(x * x + 1)); /// Returns the hyperbolic arc tangent of the given value [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Atanh(this float x) => (float)(0.5 * System.Math.Log((1 + x) / (1 - x))); #endregion #region Absolute Values /// Returns the absolute value. Basically makes negative numbers positive [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Abs(this float value) => System.Math.Abs(value); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Abs(this int value) => System.Math.Abs(value); /// Returns the absolute value, per component. Basically makes negative numbers positive [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Abs(this Vector2 v) => new Vector2(Abs(v.x), Abs(v.y)); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Abs(this Vector3 v) => new Vector3(Abs(v.x), Abs(v.y), Abs(v.z)); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 Abs(this Vector4 v) => new Vector4(Abs(v.x), Abs(v.y), Abs(v.z), Abs(v.w)); #endregion #region Clamping /// Returns the value clamped between min and max /// The value to clamp /// The minimum value /// The maximum value public static float Clamp(this float value, float min, float max) => value < min ? min : value > max ? max : value; /// Clamps each component between min and max public static Vector2 Clamp(this Vector2 v, Vector2 min, Vector2 max) => new Vector2(v.x < min.x ? min.x : v.x > max.x ? max.x : v.x, v.y < min.y ? min.y : v.y > max.y ? max.y : v.y); /// public static Vector3 Clamp(this Vector3 v, Vector3 min, Vector3 max) => new Vector3(v.x < min.x ? min.x : v.x > max.x ? max.x : v.x, v.y < min.y ? min.y : v.y > max.y ? max.y : v.y, v.z < min.z ? min.z : v.z > max.z ? max.z : v.z); /// public static Vector4 Clamp(this Vector4 v, Vector4 min, Vector4 max) => new Vector4(v.x < min.x ? min.x : v.x > max.x ? max.x : v.x, v.y < min.y ? min.y : v.y > max.y ? max.y : v.y, v.z < min.z ? min.z : v.z > max.z ? max.z : v.z, v.w < min.w ? min.w : v.w > max.w ? max.w : v.w); /// public static int Clamp(this int value, int min, int max) => value < min ? min : value > max ? max : value; /// Returns the value clamped between 0 and 1 public static float Clamp01(this float value) => value < 0f ? 0f : value > 1f ? 1f : value; /// Clamps each component between 0 and 1 public static Vector2 Clamp01(this Vector2 v) => new Vector2(v.x < 0f ? 0f : v.x > 1f ? 1f : v.x, v.y < 0f ? 0f : v.y > 1f ? 1f : v.y); /// public static Vector3 Clamp01(this Vector3 v) => new Vector3(v.x < 0f ? 0f : v.x > 1f ? 1f : v.x, v.y < 0f ? 0f : v.y > 1f ? 1f : v.y, v.z < 0f ? 0f : v.z > 1f ? 1f : v.z); /// public static Vector4 Clamp01(this Vector4 v) => new Vector4(v.x < 0f ? 0f : v.x > 1f ? 1f : v.x, v.y < 0f ? 0f : v.y > 1f ? 1f : v.y, v.z < 0f ? 0f : v.z > 1f ? 1f : v.z, v.w < 0f ? 0f : v.w > 1f ? 1f : v.w); /// Clamps the value between -1 and 1 public static float ClampNeg1To1(this float value) => value < -1f ? -1f : value > 1f ? 1f : value; /// Clamps each component between -1 and 1 public static Vector2 ClampNeg1To1(this Vector2 v) => new Vector2(v.x < -1f ? -1f : v.x > 1f ? 1f : v.x, v.y < -1f ? -1f : v.y > 1f ? 1f : v.y); /// Clamps each component between -1 and 1 public static Vector3 ClampNeg1To1(this Vector3 v) => new Vector3(v.x < -1f ? -1f : v.x > 1f ? 1f : v.x, v.y < -1f ? -1f : v.y > 1f ? 1f : v.y, v.z < -1f ? -1f : v.z > 1f ? 1f : v.z); /// Clamps each component between -1 and 1 public static Vector4 ClampNeg1To1(this Vector4 v) => new Vector4(v.x < -1f ? -1f : v.x > 1f ? 1f : v.x, v.y < -1f ? -1f : v.y > 1f ? 1f : v.y, v.z < -1f ? -1f : v.z > 1f ? 1f : v.z, v.w < -1f ? -1f : v.w > 1f ? 1f : v.w); #endregion #region Min & Max /// Returns the smallest of the two values [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Min(this float a, float b) => a < b ? a : b; /// Returns the smallest of the three values [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Min(this float a, float b, float c) => Min(Min(a, b), c); /// Returns the smallest of the four values [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Min(this float a, float b, float c, float d) => Min(Min(a, b), Min(c, d)); /// Returns the largest of the two values [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Max(this float a, float b) => a > b ? a : b; /// Returns the largest of the three values [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Max(this float a, float b, float c) => Max(Max(a, b), c); /// Returns the largest of the four values [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Max(this float a, float b, float c, float d) => Max(Max(a, b), Max(c, d)); /// Returns the smallest of the two values [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Min(this int a, int b) => a < b ? a : b; /// Returns the smallest of the three values [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Min(this int a, int b, int c) => Min(Min(a, b), c); /// Returns the smallest of the four values [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Min(this int a, int b, int c, int d) => Min(Min(a, b), Min(c, d)); /// Returns the largest of the two values [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Max(this int a, int b) => a > b ? a : b; /// Returns the largest of the three values [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Max(this int a, int b, int c) => Max(Max(a, b), c); /// Returns the largest of the four values [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Max(this int a, int b, int c, int d) => Max(Max(a, b), Max(c, d)); private static float MinCopyLinq(float[] source) { float r = float.MaxValue; for (int i = 0; i < source.Length; i++) { if (source[i] < r) r = source[i]; else if (float.IsNaN(source[i])) return source[i]; } return r; } private static int MinCopyLinq(int[] source) { int r = int.MaxValue; for (int i = 0; i < source.Length; i++) { if (source[i] < r) r = source[i]; } return r; } private static int MaxCopyLinq(int[] source) { int r = int.MinValue; for (int i = 0; i < source.Length; i++) { if (source[i] > r) r = source[i]; } return r; } private static float MaxCopyLinq(float[] source) { float r = source[0]; int startIndex = 0; for (; startIndex < source.Length; startIndex++) { if (!float.IsNaN(source[startIndex])) { r = source[startIndex]; break; } } for (int i = startIndex; i < source.Length; i++) { if (source[i] > r) r = source[i]; } return r; } /// Returns the smallest of the given values [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Min(params float[] values) => MinCopyLinq(values); /// Returns the largest of the given values [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Max(params float[] values) => MaxCopyLinq(values); /// Returns the smallest of the given values [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Min(params int[] values) => MinCopyLinq(values); /// Returns the largest of the given values [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Max(params int[] values) => MaxCopyLinq(values); /// Returns the minimum value of all components in the vector [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Min(this Vector2 v) => Min(v.x, v.y); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Min(this Vector3 v) => Min(v.x, v.y, v.z); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Min(this Vector4 v) => Min(v.x, v.y, v.z, v.w); /// Returns the maximum value of all components in the vector [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Max(this Vector2 v) => Max(v.x, v.y); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Max(this Vector3 v) => Max(v.x, v.y, v.z); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Max(this Vector4 v) => Max(v.x, v.y, v.z, v.w); #endregion #region Rounding /// Rounds the value down to the nearest integer [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Floor(this float value) => (float)System.Math.Floor(value); /// Rounds the vector components down to the nearest integer [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Floor(this Vector2 value) => new Vector2((float)System.Math.Floor(value.x), (float)System.Math.Floor(value.y)); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Floor(this Vector3 value) => new Vector3((float)System.Math.Floor(value.x), (float)System.Math.Floor(value.y), (float)System.Math.Floor(value.z)); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 Floor(this Vector4 value) => new Vector4((float)System.Math.Floor(value.x), (float)System.Math.Floor(value.y), (float)System.Math.Floor(value.z), (float)System.Math.Floor(value.w)); /// Rounds the value down to the nearest integer, returning an int value [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int FloorToInt(this float value) => (int)System.Math.Floor(value); /// Rounds the vector components down to the nearest integer, returning an integer vector [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2Int FloorToInt(this Vector2 value) => new Vector2Int((int)System.Math.Floor(value.x), (int)System.Math.Floor(value.y)); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3Int FloorToInt(this Vector3 value) => new Vector3Int((int)System.Math.Floor(value.x), (int)System.Math.Floor(value.y), (int)System.Math.Floor(value.z)); /// Rounds the value up to the nearest integer [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Ceil(this float value) => (float)System.Math.Ceiling(value); /// Rounds the vector components up to the nearest integer [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Ceil(this Vector2 value) => new Vector2((float)System.Math.Ceiling(value.x), (float)System.Math.Ceiling(value.y)); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Ceil(this Vector3 value) => new Vector3((float)System.Math.Ceiling(value.x), (float)System.Math.Ceiling(value.y), (float)System.Math.Ceiling(value.z)); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 Ceil(this Vector4 value) => new Vector4((float)System.Math.Ceiling(value.x), (float)System.Math.Ceiling(value.y), (float)System.Math.Ceiling(value.z), (float)System.Math.Ceiling(value.w)); /// Rounds the value up to the nearest integer, returning an int value [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int CeilToInt(this float value) => (int)System.Math.Ceiling(value); /// Rounds the vector components up to the nearest integer, returning an integer vector [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2Int CeilToInt(this Vector2 value) => new Vector2Int((int)System.Math.Ceiling(value.x), (int)System.Math.Ceiling(value.y)); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3Int CeilToInt(this Vector3 value) => new Vector3Int((int)System.Math.Ceiling(value.x), (int)System.Math.Ceiling(value.y), (int)System.Math.Ceiling(value.z)); /// Rounds the value to the nearest integer [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Round(this float value) => (float)System.Math.Round(value); /// Rounds the vector components to the nearest integer [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Round(this Vector2 value) => new Vector2((float)System.Math.Round(value.x), (float)System.Math.Round(value.y)); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Round(this Vector3 value) => new Vector3((float)System.Math.Round(value.x), (float)System.Math.Round(value.y), (float)System.Math.Round(value.z)); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 Round(this Vector4 value) => new Vector4((float)System.Math.Round(value.x), (float)System.Math.Round(value.y), (float)System.Math.Round(value.z), (float)System.Math.Round(value.w)); /// Rounds the value to the nearest value, snapped to the given interval size [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Round(this float value, float snapInterval) => Mathf.Round(value / snapInterval) * snapInterval; /// Rounds the vector components to the nearest value, snapped to the given interval size [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Round(this Vector2 value, float snapInterval) => new Vector2(Round(value.x, snapInterval), Round(value.y, snapInterval)); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Round(this Vector3 value, float snapInterval) => new Vector3(Round(value.x, snapInterval), Round(value.y, snapInterval), Round(value.z, snapInterval)); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 Round(this Vector4 value, float snapInterval) => new Vector4(Round(value.x, snapInterval), Round(value.y, snapInterval), Round(value.z, snapInterval), Round(value.w, snapInterval)); /// Rounds the value to the nearest integer, returning an int value [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int RoundToInt(this float value) => (int)System.Math.Round(value); /// Rounds the vector components to the nearest integer, returning an integer vector [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2Int RoundToInt(this Vector2 value) => new Vector2Int((int)System.Math.Round(value.x), (int)System.Math.Round(value.y)); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3Int RoundToInt(this Vector3 value) => new Vector3Int((int)System.Math.Round(value.x), (int)System.Math.Round(value.y), (int)System.Math.Round(value.z)); #endregion #region Repeat /// Repeats the given value in the interval specified by length [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Repeat(this float value, float length) => Clamp(value - Floor(value / length) * length, 0.0f, length); /// Repeats a value within a range, going back and forth [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float PingPong(float t, float length) => length - Abs(Repeat(t, length * 2f) - length); #endregion #region Smoothing /// Applies cubic smoothing to the 0-1 interval, also known as the smoothstep function. Similar to an EaseInOut operation [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Smooth01(float x) => x * x * (3 - 2 * x); /// Applies quintic smoothing to the 0-1 interval, also known as the smootherstep function. Similar to an EaseInOut operation [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Smoother01(float x) => x * x * x * (x * (x * 6 - 15) + 10); /// Applies trigonometric smoothing to the 0-1 interval. Similar to an EaseInOut operation [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float SmoothCos01(float x) => Cos(x * PI) * -0.5f + 0.5f; /// 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 public static float Gamma(float value, float absmax, float gamma) { bool negative = value < 0F; float absval = Abs(value); if (absval > absmax) return negative ? -absval : absval; float result = Pow(absval / absmax, gamma) * absmax; return negative ? -result : result; } /// Gradually changes a value towards a desired goal over time. /// The value is smoothed by some spring-damper like function, which will never overshoot. /// The function can be used to smooth any kind of value, positions, colors, scalars /// The current position /// The position we are trying to reach /// The current velocity, this value is modified by the function every time you call it /// Approximately the time it will take to reach the target. A smaller value will reach the target faster /// Optionally allows you to clamp the maximum speed public static float SmoothDamp(float current, float target, ref float currentVelocity, float smoothTime, float maxSpeed = Infinity) { float deltaTime = Time.deltaTime; return SmoothDamp(current, target, ref currentVelocity, smoothTime, maxSpeed, deltaTime); } /// Gradually changes a value towards a desired goal over time. /// The value is smoothed by some spring-damper like function, which will never overshoot. /// The function can be used to smooth any kind of value, positions, colors, scalars /// The current position /// The position we are trying to reach /// The current velocity, this value is modified by the function every time you call it /// Approximately the time it will take to reach the target. A smaller value will reach the target faster /// Optionally allows you to clamp the maximum speed /// The time since the last call to this function. By default Time.deltaTime public static float SmoothDamp( float current, float target, ref float currentVelocity, float smoothTime, [UnityEngine.Internal.DefaultValue("Mathf.Infinity")] float maxSpeed, [UnityEngine.Internal.DefaultValue("Time.deltaTime")] float deltaTime) { // Based on Game Programming Gems 4 Chapter 1.10 smoothTime = Mathf.Max(0.0001F, smoothTime); float omega = 2F / smoothTime; float x = omega * deltaTime; float exp = 1F / (1F + x + 0.48F * x * x + 0.235F * x * x * x); float change = current - target; float originalTo = target; // Clamp maximum speed float maxChange = maxSpeed * smoothTime; change = Mathf.Clamp(change, -maxChange, maxChange); target = current - change; float temp = (currentVelocity + omega * change) * deltaTime; currentVelocity = (currentVelocity - omega * temp) * exp; float output = target + (change + temp) * exp; // Prevent overshooting if (originalTo - current > 0.0F == output > originalTo) { output = originalTo; currentVelocity = (output - originalTo) / deltaTime; } return output; } #endregion #region Value & Vector interpolation /// 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 /// The start value, when t is 0 /// The start value, when t is 1 /// The t-value from 0 to 1 representing position along the lerp [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Lerp(float a, float b, float t) => (1f - t) * a + t * b; /// 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 /// The start value, when t is 0 /// The start value, when t is 1 /// The t-values from 0 to 1 representing position along the lerp [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Lerp(Vector2 a, Vector2 b, Vector2 t) => new Vector2(Lerp(a.x, b.x, t.x), Lerp(a.y, b.y, t.y)); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Lerp(Vector3 a, Vector3 b, Vector3 t) => new Vector3(Lerp(a.x, b.x, t.x), Lerp(a.y, b.y, t.y), Lerp(a.z, b.z, t.z)); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 Lerp(Vector4 a, Vector4 b, Vector4 t) => new Vector4(Lerp(a.x, b.x, t.x), Lerp(a.y, b.y, t.y), Lerp(a.z, b.z, t.z), Lerp(a.w, b.w, t.w)); /// Linearly blends between two rectangles, moving and resizing from the center. Note: this lerp is unclamped /// The start value, when t is 0 /// The start value, when t is 1 /// The t-values from 0 to 1 representing position along the lerp public static Rect Lerp(Rect a, Rect b, float t) { Vector2 center = Vector2.LerpUnclamped(a.center, b.center, t); Vector2 size = Vector2.LerpUnclamped(a.size, b.size, t); return new Rect(default, size) { center = center }; } /// 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 /// The start value, when t is 0 /// The start value, when t is 1 /// The t-value from 0 to 1 representing position along the lerp, clamped between 0 and 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float LerpClamped(float a, float b, float t) => Lerp(a, b, Clamp01(t)); /// Lerps between a and b, applying cubic smoothing to the t-value /// The start value, when t is 0 /// The start value, when t is 1 /// The t-value from 0 to 1 representing position along the lerp, clamped between 0 and 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float LerpSmooth(float a, float b, float t) => Lerp(a, b, Smooth01(Clamp01(t))); /// Given a value between a and b, returns its normalized location in that range, as a t-value (interpolant) from 0 to 1 /// The start of the range, where it would return 0 /// The end of the range, where it would return 1 /// A value between a and b. Note: values outside this range are still valid, and will be extrapolated [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float InverseLerp(float a, float b, float value) => (value - a) / (b - a); /// Given a value between a and b, returns its normalized location in that range, as a t-value (interpolant) from 0 to 1. /// This safe version returns 0 if a == b, instead of a division by zero /// The start of the range, where it would return 0 /// The end of the range, where it would return 1 /// A value between a and b. Note: values outside this range are still valid, and will be extrapolated [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float InverseLerpSafe(float a, float b, float value) { float den = b - a; if (den == 0) return 0; return (value - a) / den; } /// 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 /// The start of the ranges, where it would return 0 /// The end of the ranges, where it would return 1 /// A value between a and b. Note: values outside this range are still valid, and will be extrapolated [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 InverseLerp(Vector2 a, Vector2 b, Vector2 v) => new Vector2((v.x - a.x) / (b.x - a.x), (v.y - a.y) / (b.y - a.y)); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 InverseLerp(Vector3 a, Vector3 b, Vector3 v) => 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)); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 InverseLerp(Vector4 a, Vector4 b, Vector4 v) => 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), (v.w - a.w) / (b.w - a.w)); /// Given a value between a and b, returns its normalized location in that range, as a t-value (interpolant) clamped between 0 and 1 /// The start of the range, where it would return 0 /// The end of the range, where it would return 1 /// A value between a and b [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float InverseLerpClamped(float a, float b, float value) => Clamp01((value - a) / (b - a)); /// 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. /// Equivalent to "smoothstep" in shader code /// The start of the range, where it would return 0 /// The end of the range, where it would return 1 /// A value between a and b. Note: values outside this range are still valid, and will be extrapolated [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float InverseLerpSmooth(float a, float b, float value) => Smooth01(Clamp01((value - a) / (b - a))); /// Remaps a value from the input range [iMin to iMax] into the output range [oMin to oMax]. /// Equivalent to Lerp(oMin,oMax,InverseLerp(iMin,iMax,value)) /// The start value of the input range /// The end value of the input range /// The start value of the output range /// The end value of the output range /// The value to remap [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Remap(float iMin, float iMax, float oMin, float oMax, float value) => Lerp(oMin, oMax, InverseLerp(iMin, iMax, value)); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Remap(float iMin, float iMax, float oMin, float oMax, int value) => Lerp(oMin, oMax, InverseLerp(iMin, iMax, value)); /// Remaps values from the input range [iMin to iMax] into the output range [oMin to oMax] on a per-component basis. /// Equivalent to Lerp(oMin,oMax,InverseLerp(iMin,iMax,value)) /// The start values of the input ranges /// The end values of the input ranges /// The start values of the output ranges /// The end values of the output ranges /// The values to remap [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Remap(Vector2 iMin, Vector2 iMax, Vector2 oMin, Vector2 oMax, Vector2 value) => Lerp(oMin, oMax, InverseLerp(iMin, iMax, value)); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Remap(Vector3 iMin, Vector3 iMax, Vector3 oMin, Vector3 oMax, Vector3 value) => Lerp(oMin, oMax, InverseLerp(iMin, iMax, value)); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 Remap(Vector4 iMin, Vector4 iMax, Vector4 oMin, Vector4 oMax, Vector4 value) => Lerp(oMin, oMax, InverseLerp(iMin, iMax, value)); /// 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. /// Equivalent to Lerp(oMin,oMax,InverseLerpClamped(iMin,iMax,value)) /// The start value of the input range /// The end value of the input range /// The start value of the output range /// The end value of the output range /// The value to remap [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float RemapClamped(float iMin, float iMax, float oMin, float oMax, float value) => Lerp(oMin, oMax, InverseLerpClamped(iMin, iMax, value)); /// Remaps a value from the input Rect to the output Rect /// The input Rect /// The output Rect /// The input position in the input Rect space [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Remap(Rect iRect, Rect oRect, Vector2 iPos) => Remap(iRect.min, iRect.max, oRect.min, oRect.max, iPos); /// Remaps a value from the input Bounds to the output Bounds /// The input Bounds /// The output Bounds /// The input position in the input Bounds space [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Remap(Bounds iBounds, Bounds oBounds, Vector3 iPos) => Remap(iBounds.min, iBounds.max, oBounds.min, oBounds.max, iPos); /// Exponential interpolation, the multiplicative version of lerp, useful for values such as scaling or zooming /// The start value /// The end value /// The t-value from 0 to 1 representing position along the eerp [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Eerp(float a, float b, float t) => Mathf.Pow(a, 1 - t) * Mathf.Pow(b, t); /// Inverse exponential interpolation, the multiplicative version of InverseLerp, useful for values such as scaling or zooming /// The start value /// The end value /// A value between a and b. Note: values outside this range are still valid, and will be extrapolated [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float InverseEerp(float a, float b, float v) => Mathf.Log(a / v) / Mathf.Log(a / b); #endregion #region Angle /// Returns the angle of this vector, in radians /// The vector to get the angle of. It does not have to be normalized [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Angle(this Vector2 v) => Mathf.Atan2(v.y, v.x); /// Get the angle in degrees off the forward defined by x. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Angle(this float x, float y) => Mathf.Atan2(y, x); public static Vector2 Reflect(this Vector2 v, Vector2 normal) { var dp = 2 * Vector2.Dot(v, normal); return new Vector2(v.x - normal.x * dp, v.y - normal.y * dp); } public static void Mirror(this ref Vector2 v, Vector2 axis) { v = (2 * (Vector2.Dot(v, axis) / Vector2.Dot(axis, axis)) * axis) - v; } public static Vector2 Mirror(this Vector2 v, Vector2 axis) { return (2 * (Vector2.Dot(v, axis) / Vector2.Dot(axis, axis)) * axis) - v; } /// /// Angular interpolates between two vectors. /// /// /// /// /// The vectors are 2 dimensional, so technically this is not a spherical linear interpolation. The name Slerp is kept for consistency. /// 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 /// magnitude interpolates at a linear rate. public static Vector2 Slerp(this Vector2 from, Vector2 to, float t) { var a = NormalizeAngle(Lerp(Atan2(from.y, from.x), Atan2(to.y, to.x), t), true); var l = Mathf.LerpUnclamped(from.magnitude, to.magnitude, t); return new Vector2(Cos(a) * l, Sin(a) * l); } /// /// Angular interpolates between two vectors. /// /// /// /// /// The vectors are 2 dimensional, so technically this is not a spherical linear interpolation. The name Slerp is kept for consistency. /// 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 /// magnitude interpolates at a linear rate. public static Vector2 SlerpClamped(this Vector2 from, Vector2 to, float t) { var a = NormalizeAngle(Lerp(Atan2(from.y, from.x), Atan2(to.y, to.x), t), true); var l = Lerp(from.magnitude, to.magnitude, t); return new Vector2(Cos(a) * l, Sin(a) * l); } /// Returns the shortest angle between a and b, in the range 0 to tau/2 (0 to pi) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float AngleBetween(this Vector2 a, Vector2 b) => Mathf.Acos(Vector2.Dot(a.normalized, b.normalized).ClampNeg1To1()); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float AngleBetween(this Vector3 a, Vector3 b) => Mathf.Acos(Vector3.Dot(a.normalized, b.normalized).ClampNeg1To1()); /// /// set an angle with in the bounds of -PI to PI /// /// /// /// /// public static float NormalizeAngle(this float angle, bool useRadians = true) { float rd = (useRadians ? PI : 180); return Wrap(angle, rd, -rd); } public static float ClampIn180(this float a, bool bUseRadians = false) { return NormalizeAngle(a, bUseRadians); } public static float ClampIn360(this float a, bool bUseRadians = false) { a = NormalizeAngle(a, bUseRadians); if (a < 0f) a += (bUseRadians) ? TWO_PI : 360.0f; return a; } /// Blends between the aRad and bRad angles, based on the input t-value between 0 and 1 /// The start value, in radians /// The end value, in radians /// The t-value between 0 and 1 public static float LerpAngle(this float aRad, float bRad, float t) { float delta = Repeat((bRad - aRad), TWO_PI); if (delta > PI) delta -= TWO_PI; return aRad + delta * Clamp01(t); } /// Returns the shortest angle between the two input angles, in radians [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float DeltaAngle(this float a, float b) => (b - a + PI).Repeat(TWO_PI) - PI; /// Given an angle between a and b, returns its normalized location in that range, as a t-value (interpolant) from 0 to 1 /// The start angle of the range (in radians), where it would return 0 /// The end angle of the range (in radians), where it would return 1 /// An angle between a and b public static float InverseLerpAngle(this float a, float b, float v) { float angBetween = DeltaAngle(a, b); b = a + angBetween; // removes any a->b discontinuity float h = a + angBetween * 0.5f; // halfway angle v = h + DeltaAngle(h, v); // get offset from h, and offset by h return InverseLerpClamped(a, b, v); } /// Gradually changes an angle given in radians towards a desired goal angle over time. /// The value is smoothed by some spring-damper like function. /// The function can be used to smooth any kind of value, positions, colors, scalars. The most common use is for smoothing a follow camera. /// The current angle /// The angle we are trying to reach /// The current angular velocity, this value is modified by the function every time you call it /// Approximately the time it will take to reach the target. A smaller value will reach the target faster /// Optionally allows you to clamp the maximum speed public static float SmoothDampAngle(this float current, float target, ref float currentVelocity, float smoothTime, float maxSpeed = Infinity) { float deltaTime = Time.deltaTime; return SmoothDampAngle(current, target, ref currentVelocity, smoothTime, maxSpeed, deltaTime); } /// Gradually changes an angle given in radians towards a desired goal angle over time. /// The value is smoothed by some spring-damper like function. /// The function can be used to smooth any kind of value, positions, colors, scalars. The most common use is for smoothing a follow camera. /// The current angle /// The angle we are trying to reach /// The current angular velocity, this value is modified by the function every time you call it /// Approximately the time it will take to reach the target. A smaller value will reach the target faster /// Optionally allows you to clamp the maximum speed /// The time since the last call to this function. By default Time.deltaTime public static float SmoothDampAngle( this float current, float target, ref float currentVelocity, float smoothTime, [UnityEngine.Internal.DefaultValue("Mathf.Infinity")] float maxSpeed, [UnityEngine.Internal.DefaultValue("Time.deltaTime")] float deltaTime) { target = current + DeltaAngle(current, target); return SmoothDamp(current, target, ref currentVelocity, smoothTime, maxSpeed, deltaTime); } #endregion #region Wrap public enum WrapMode { Oblivion = 0, Clamp = 1, Loop = 2, PingPong = 3 } /// /// Wraps a value around some significant range. /// /// Similar to C# modulo, but works like a true module, in a unary direction over any range (including negative values). /// /// ex: /// Wrap(8,6,2) == 4 /// Wrap(4,2,0) == 0 /// Wrap(4,2,-2) == 0 /// /// value to wrap /// max in range /// min in range /// A value wrapped around min to max /// public static int Wrap(this int value, int max, int min) { max -= min; if (max == 0) return min; var result = (value - min) % max; return result < 0 ? result + max + min : result + min; } public static int Wrap(this int value, int max) { var result = value % max; return result < 0 ? result + max : result; } public static long Wrap(this long value, long max, long min) { max -= min; if (max == 0) return min; var result = (value - min) % max; return result < 0 ? result + max + min : result + min; } public static long Wrap(long value, long max) { var result = value % max; return result < 0 ? result + max : result; } public static float Wrap(this float value, float max, float min) { max -= min; if (max == 0) return min; var result = (value - min) % max; return result < 0 ? result + max + min : result + min; } public static float Wrap(this float value, float max) { var result = value % max; return result < 0 ? result + max : result; } public static double Wrap(this double value, double max, double min) { max -= min; if (max == 0) return min; var result = (value - min) % max; return result < 0 ? result + max + min : result + min; } public static double Wrap(this double value, double max) { var result = value % max; return result < 0 ? result + max : result; } /// /// Wrap an index by some mode /// /// /// /// /// public static int WrapIndex(WrapMode mode, int value, int max) { switch (mode) { case WrapMode.Clamp: return Clamp(value, 0, max - 1); case WrapMode.Loop: return Wrap(value, max); case WrapMode.PingPong: return (int)PingPong(value, max - 1); default: return value; } } public static float Wrap(WrapMode mode, int value, int max, int min = 0) { switch (mode) { case WrapMode.Clamp: return Clamp(value, min, max); case WrapMode.Loop: return Wrap(value, max, min); case WrapMode.PingPong: return (int)PingPong(value - min, max - min) + min; default: return value; } } public static float Wrap(WrapMode mode, float value, float max, float min = 0) { switch (mode) { case WrapMode.Clamp: return Clamp(value, min, max - 1); case WrapMode.Loop: return Wrap(value, max, min); case WrapMode.PingPong: return (int)PingPong(value - min, max - min - 1) + min; default: return value; } } #endregion } } ================================================ FILE: VirtueSky/Misc/Common.Math.cs.meta ================================================ fileFormatVersion: 2 guid: f897424e6b154873aff43970d12790bb timeCreated: 1723799321 ================================================ FILE: VirtueSky/Misc/Common.Physics.cs ================================================ using System.Collections.Generic; using UnityEngine; namespace VirtueSky.Misc { public static partial class Common { #region IgnoreCollision public static void IgnoreCollision(List _listCollider, Collider _collider) { _listCollider.ForEach(col => { Physics.IgnoreCollision(col, _collider); }); } public static void IgnoreCollision(Collider _collider, List _listCollider) { _listCollider.ForEach(col => { Physics.IgnoreCollision(col, _collider); }); } public static void IgnoreCollision(List _listCollider1, List _listCollider2) { foreach (var VARIABLE1 in _listCollider1) { foreach (var VARIABLE2 in _listCollider2) { Physics.IgnoreCollision(VARIABLE1, VARIABLE2); } } } public static void IgnoreCollision2D(List _listCollider, Collider2D _collider) { foreach (var VARIABLE in _listCollider) { Physics2D.IgnoreCollision(VARIABLE, _collider); } } public static void IgnoreCollision2D(Collider2D _collider, List _listCollider) { foreach (var VARIABLE in _listCollider) { Physics2D.IgnoreCollision(VARIABLE, _collider); } } public static void IgnoreCollision2D(List _listCollider1, List _listCollider2) { foreach (var VARIABLE1 in _listCollider1) { foreach (var VARIABLE2 in _listCollider2) { Physics2D.IgnoreCollision(VARIABLE1, VARIABLE2); } } } #endregion } } ================================================ FILE: VirtueSky/Misc/Common.Physics.cs.meta ================================================ fileFormatVersion: 2 guid: f8f668bda2394a7eb6ee3d51ce842d1a timeCreated: 1699243844 ================================================ FILE: VirtueSky/Misc/Common.SkeletonAnimation.cs ================================================ using System; using System.Collections.Generic; #if VIRTUESKY_SKELETON using Spine; using Spine.Unity; using UnityEngine; using VirtueSky.Core; using Animation = Spine.Animation; namespace VirtueSky.Misc { public static partial class Common { public static float Duration(this SkeletonAnimation skeletonAnimation, string animationName) { Animation animation = null; foreach (var animationsItem in skeletonAnimation.AnimationState.Data.SkeletonData.Animations.Items) { if (animationsItem.Name.Equals(animationName)) { animation = animationsItem; break; } } if (animation == null) return 0; return animation.Duration; } public static float Duration(this SkeletonAnimation skeletonAnimation, int track = 0) { var animation = skeletonAnimation.AnimationState.GetCurrent(track); if (animation == null) return 0; return animation.Animation.Duration; } public static SkeletonAnimation OnComplete(this SkeletonAnimation skeletonAnimation, Action onComplete, int trackIndex = 0, MonoBehaviour target = null) { App.Delay(target != null ? target : skeletonAnimation, skeletonAnimation.Duration(trackIndex), () => { if (skeletonAnimation != null) { onComplete?.Invoke(); } }); return skeletonAnimation; } public static SkeletonAnimation OnUpdate(this SkeletonAnimation skeletonAnimation, Action onUpdate, int trackIndex = 0, MonoBehaviour target = null) { App.Delay(target != null ? target : skeletonAnimation, skeletonAnimation.Duration(trackIndex), null, onUpdate); return skeletonAnimation; } public static TrackEntry OnComplete(this TrackEntry trackEntry, Action onComplete) { trackEntry.Complete += HandleComplete; void HandleComplete(TrackEntry track) { trackEntry.Complete -= HandleComplete; onComplete?.Invoke(); } return trackEntry; } public static SkeletonAnimation Play(this SkeletonAnimation skeletonAnimation, string animationName, bool loop = false, int trackIndex = 0, float timeScale = 1f) { skeletonAnimation.ClearState(); skeletonAnimation.AnimationName = animationName; skeletonAnimation.loop = loop; var trackEntry = skeletonAnimation.AnimationState.SetAnimation(trackIndex, animationName, loop); trackEntry.TimeScale = timeScale; skeletonAnimation.LateUpdate(); skeletonAnimation.Initialize(true); return skeletonAnimation; } public static SkeletonAnimation PlayOnly(this SkeletonAnimation skeletonAnimation, string animationName, bool loop = false, int trackIndex = 0, float timeScale = 1f) { skeletonAnimation.AnimationName = animationName; var trackEntry = skeletonAnimation.AnimationState.SetAnimation(trackIndex, animationName, loop); trackEntry.TimeScale = timeScale; return skeletonAnimation; } public static SkeletonAnimation AddAnimation(this SkeletonAnimation skeletonAnimation, int trackIndex, string animationName, bool loop, float timeDelay = 0f, float mixDuration = 0f, float timeScale = 1f) { var track = skeletonAnimation.AnimationState.AddAnimation(trackIndex, animationName, loop, timeDelay); track.MixDuration = mixDuration; track.TimeScale = timeScale; return skeletonAnimation; } public static SkeletonAnimation SetSkin(this SkeletonAnimation skeletonAnimation, string skinName) { var skin = new Skin("temp"); skin.AddSkin(skeletonAnimation.skeleton.Data.FindSkin(skinName)); skeletonAnimation.initialSkinName = "temp"; skeletonAnimation.skeleton.SetSkin(skin); skeletonAnimation.skeleton.SetSlotsToSetupPose(); skeletonAnimation.LateUpdate(); skeletonAnimation.AnimationState.Apply(skeletonAnimation.skeleton); return skeletonAnimation; } public static SkeletonAnimation SetSkin(this SkeletonAnimation skeletonAnimation, List skinNames) { var skin = new Skin("temp"); var skeletonData = skeletonAnimation.Skeleton.Data; foreach (string skinName in skinNames) { skin.AddSkin(skeletonData.FindSkin(skinName)); } skeletonAnimation.initialSkinName = "temp"; skeletonAnimation.skeleton.SetSkin(skin); skeletonAnimation.skeleton.SetSlotsToSetupPose(); skeletonAnimation.LateUpdate(); skeletonAnimation.AnimationState.Apply(skeletonAnimation.skeleton); return skeletonAnimation; } public static SkeletonAnimation ChangeAttachment(this SkeletonAnimation skeletonAnimation, string slotName, string attachmentName) { var slotIndex = skeletonAnimation.skeleton.Data.FindSlot(slotName).Index; var attachment = skeletonAnimation.skeleton.GetAttachment(slotIndex, attachmentName); var skin = new Skin("temp"); skin.SetAttachment(slotIndex, slotName, attachment); skeletonAnimation.skeleton.SetSkin(skin); skeletonAnimation.skeleton.SetSlotsToSetupPose(); skeletonAnimation.LateUpdate(); return skeletonAnimation; } public static SkeletonAnimation ChangeAttachment(this SkeletonAnimation skeletonAnimation, string slotName, List attachmentNames) { var slotIndex = skeletonAnimation.skeleton.Data.FindSlot(slotName).Index; var skin = new Skin("temp"); foreach (var attachmentName in attachmentNames) { var attachment = skeletonAnimation.skeleton.GetAttachment(slotIndex, attachmentName); skin.SetAttachment(slotIndex, slotName, attachment); } skeletonAnimation.skeleton.SetSkin(skin); skeletonAnimation.skeleton.SetSlotsToSetupPose(); skeletonAnimation.LateUpdate(); return skeletonAnimation; } public static SkeletonAnimation MixSkin(this SkeletonAnimation skeletonAnimation, string mixSkinName) { Skin skin = new Skin("temp"); skin.AddSkin(skeletonAnimation.Skeleton.Data.FindSkin(mixSkinName)); skeletonAnimation.Skeleton.SetSkin(skin); skeletonAnimation.Skeleton.SetSlotsToSetupPose(); skeletonAnimation.AnimationState.Apply(skeletonAnimation.Skeleton); return skeletonAnimation; } public static SkeletonAnimation MixSkin(this SkeletonAnimation skeletonAnimation, List mixSkinNames) { Skin skin = new Skin("temp"); foreach (var mixSkinName in mixSkinNames) { skin.AddSkin(skeletonAnimation.Skeleton.Data.FindSkin(mixSkinName)); } skeletonAnimation.Skeleton.SetSkin(skin); skeletonAnimation.Skeleton.SetSlotsToSetupPose(); skeletonAnimation.AnimationState.Apply(skeletonAnimation.Skeleton); return skeletonAnimation; } } } #endif ================================================ FILE: VirtueSky/Misc/Common.SkeletonAnimation.cs.meta ================================================ fileFormatVersion: 2 guid: f264a02e80144c4d8eb55c2064ab5032 timeCreated: 1708065730 ================================================ FILE: VirtueSky/Misc/Common.SkeletonGraphic.cs ================================================ using System; using System.Collections.Generic; #if VIRTUESKY_SKELETON using Spine; using Spine.Unity; using UnityEngine; using VirtueSky.Core; using Animation = Spine.Animation; namespace VirtueSky.Misc { public static partial class Common { public static float Duration(this SkeletonGraphic skeletonGraphic, string animationName) { Animation animation = null; foreach (var animationsItem in skeletonGraphic.AnimationState.Data.SkeletonData.Animations.Items) { if (animationsItem.Name.Equals(animationName)) { animation = animationsItem; break; } } if (animation == null) return 0; return animation.Duration; } public static float Duration(this SkeletonGraphic skeletonGraphic, int track = 0) { var animation = skeletonGraphic.AnimationState.GetCurrent(track); if (animation == null) return 0; return animation.Animation.Duration; } public static SkeletonGraphic OnComplete(this SkeletonGraphic skeletonGraphic, Action onComplete, int trackIndex = 0, MonoBehaviour target = null) { App.Delay(target != null ? target : skeletonGraphic, skeletonGraphic.Duration(trackIndex), () => { if (skeletonGraphic != null) { onComplete?.Invoke(); } }); return skeletonGraphic; } public static SkeletonGraphic OnUpdate(this SkeletonGraphic skeletonGraphic, Action onUpdate, int trackIndex = 0, MonoBehaviour target = null) { App.Delay(target != null ? target : skeletonGraphic, skeletonGraphic.Duration(trackIndex), null, onUpdate); return skeletonGraphic; } public static SkeletonGraphic Play(this SkeletonGraphic skeletonGraphic, string animationName, bool loop = false, int trackIndex = 0, float timeScale = 1f) { skeletonGraphic.Clear(); skeletonGraphic.startingAnimation = animationName; skeletonGraphic.startingLoop = loop; var trackEntry = skeletonGraphic.AnimationState.SetAnimation(trackIndex, animationName, loop); trackEntry.TimeScale = timeScale; skeletonGraphic.LateUpdate(); skeletonGraphic.Initialize(true); return skeletonGraphic; } public static SkeletonGraphic PlayOnly(this SkeletonGraphic skeletonGraphic, string animationName, bool loop = false, int trackIndex = 0, float timeScale = 1f) { skeletonGraphic.startingAnimation = animationName; var trackEntry = skeletonGraphic.AnimationState.SetAnimation(trackIndex, animationName, loop); trackEntry.TimeScale = timeScale; return skeletonGraphic; } public static SkeletonGraphic AddAnimation(this SkeletonGraphic skeletonGraphic, int trackIndex, string animationName, bool loop, float timeDelay = 0f, float mixDuration = 0f, float timeScale = 1f) { var track = skeletonGraphic.AnimationState.AddAnimation(trackIndex, animationName, loop, timeDelay); track.MixDuration = mixDuration; track.TimeScale = timeScale; return skeletonGraphic; } public static SkeletonGraphic SetSkin(this SkeletonGraphic skeletonGraphic, string skinName) { var skin = new Skin("temp"); skin.AddSkin(skeletonGraphic.Skeleton.Data.FindSkin(skinName)); skeletonGraphic.Skeleton.SetSkin(skin); skeletonGraphic.Skeleton.SetSlotsToSetupPose(); skeletonGraphic.LateUpdate(); skeletonGraphic.AnimationState.Apply(skeletonGraphic.Skeleton); return skeletonGraphic; } public static SkeletonGraphic SetSkin(this SkeletonGraphic skeletonGraphic, List skinNames) { var skin = new Skin("temp"); var skeletonData = skeletonGraphic.Skeleton.Data; foreach (string skinName in skinNames) { skin.AddSkin(skeletonData.FindSkin(skinName)); } skeletonGraphic.initialSkinName = "temp"; skeletonGraphic.Skeleton.SetSkin(skin); skeletonGraphic.Skeleton.SetSlotsToSetupPose(); skeletonGraphic.LateUpdate(); skeletonGraphic.AnimationState.Apply(skeletonGraphic.Skeleton); return skeletonGraphic; } public static SkeletonGraphic ChangeAttachment(this SkeletonGraphic skeletonGraphic, string slotName, string attachmentName) { var slotIndex = skeletonGraphic.Skeleton.Data.FindSlot(slotName).Index; var attachment = skeletonGraphic.Skeleton.GetAttachment(slotIndex, attachmentName); var skin = new Skin("temp"); skin.SetAttachment(slotIndex, slotName, attachment); skeletonGraphic.Skeleton.SetSkin(skin); skeletonGraphic.Skeleton.SetSlotsToSetupPose(); skeletonGraphic.LateUpdate(); return skeletonGraphic; } public static SkeletonGraphic ChangeAttachment(this SkeletonGraphic skeletonGraphic, string slotName, List attachmentNames) { var slotIndex = skeletonGraphic.Skeleton.Data.FindSlot(slotName).Index; var skin = new Skin("temp"); foreach (var attachmentName in attachmentNames) { var attachment = skeletonGraphic.Skeleton.GetAttachment(slotIndex, attachmentName); skin.SetAttachment(slotIndex, slotName, attachment); } skeletonGraphic.Skeleton.SetSkin(skin); skeletonGraphic.Skeleton.SetSlotsToSetupPose(); skeletonGraphic.LateUpdate(); return skeletonGraphic; } public static SkeletonGraphic MixSkin(this SkeletonGraphic skeletonGraphic, string mixSkinName) { Skin skin = new Skin("temp"); skin.AddSkin(skeletonGraphic.Skeleton.Data.FindSkin(mixSkinName)); skeletonGraphic.Skeleton.SetSkin(skin); skeletonGraphic.Skeleton.SetSlotsToSetupPose(); skeletonGraphic.AnimationState.Apply(skeletonGraphic.Skeleton); return skeletonGraphic; } public static SkeletonGraphic MixSkin(this SkeletonGraphic skeletonGraphic, List mixSkinNames) { Skin skin = new Skin("temp"); foreach (var mixSkinName in mixSkinNames) { skin.AddSkin(skeletonGraphic.Skeleton.Data.FindSkin(mixSkinName)); } skeletonGraphic.Skeleton.SetSkin(skin); skeletonGraphic.Skeleton.SetSlotsToSetupPose(); skeletonGraphic.AnimationState.Apply(skeletonGraphic.Skeleton); return skeletonGraphic; } } } #endif ================================================ FILE: VirtueSky/Misc/Common.SkeletonGraphic.cs.meta ================================================ fileFormatVersion: 2 guid: 1c6229e62edb46d5abee83d47f591741 timeCreated: 1708067235 ================================================ FILE: VirtueSky/Misc/Common.Tag.cs ================================================ using System.Linq; using UnityEngine; namespace VirtueSky.Misc { public static partial class Common { public static T FindComponentInChildWithTag(this GameObject parent, string tag) where T : Component { Transform t = parent.transform; foreach (Transform tr in t) { if (tr.tag == tag) { return tr.GetComponent(); } } return null; } public static GameObject SetLayerForAllChildObject(this GameObject obj, int layerIndex) { obj.layer = layerIndex; obj.GetComponentsInChildren().ToList().ForEach(x => { x.gameObject.layer = layerIndex; }); return obj; } public static GameObject SetLayer(this GameObject obj, int layerIndex) { obj.layer = layerIndex; return obj; } public static GameObject SetTagForAllChildObject(this GameObject obj, string tag) { obj.tag = tag; obj.GetComponentsInChildren().ToList().ForEach(x => { x.gameObject.tag = tag; }); return obj; } public static GameObject SetTag(this GameObject obj, string tag) { obj.gameObject.tag = tag; return obj; } } } ================================================ FILE: VirtueSky/Misc/Common.Tag.cs.meta ================================================ fileFormatVersion: 2 guid: 7a60703267c2469f8401ae2860c92fd9 timeCreated: 1699240721 ================================================ FILE: VirtueSky/Misc/Common.Text.cs ================================================ using System.Runtime.CompilerServices; using UnityEngine; using VirtueSky.Utils; namespace VirtueSky.Misc { public partial class Common { /// /// /// /// /// html color, not include # /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string SetColor(this string text, string color) { return $"{text}"; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string SetColor(this string text, UnityEngine.Color color) { return $"{text}"; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string SetColor(this string text, CustomColor customColor) { Color color = customColor.ToColor(); return $"{text}"; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string SetSize(this string text, int size) { return $"{text}"; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string ToBold(this string text) { return $"{text}"; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string ToItalic(this string text) { return $"{text}"; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string ToWhiteBold(this string text) { return text.ToBold().SetColor(UnityEngine.Color.white); } } } ================================================ FILE: VirtueSky/Misc/Common.Text.cs.meta ================================================ fileFormatVersion: 2 guid: 86de5ed581ce4424a9f394e8a6fe63ec timeCreated: 1729224673 ================================================ FILE: VirtueSky/Misc/Common.Transform.cs ================================================ using System; using PrimeTween; using UnityEngine; namespace VirtueSky.Misc { public static partial class Common { public static Transform ClearTransform(this Transform transform) { var childs = transform.childCount; for (int i = childs - 1; i >= 0; i--) { UnityEngine.Object.DestroyImmediate(transform.GetChild(i).gameObject, true); } return transform; } public static void Shrug(this Transform transformObj, float time, float strength = .1f, Ease easingTypes = Ease.OutQuad, Action completed = null) { Tween tween = default; Vector3 baseScale = transformObj.localScale; Vector3 targetBounceX = new Vector3(1 + strength, 1 - strength) * baseScale.x; Vector3 targetBounceY = new Vector3(1 - strength, 1 + strength) * baseScale.y; tween = Tween.Scale(transformObj, targetBounceX, time / 3, easingTypes).OnComplete(() => { Tween.Scale(transformObj, targetBounceY, time / 3, easingTypes).OnComplete(() => { Tween.Scale(transformObj, baseScale, time / 3, easingTypes).OnComplete(() => { tween.Stop(); completed?.Invoke(); }); }); }); } public static Camera CameraShake(this Camera camera, float strengthFactor = 1.0f, float duration = 0.5f, int frequency = 10) { Tween.ShakeCamera(camera, strengthFactor, duration, frequency); return camera; } /// /// Convert UI positon to world position /// /// transform is transform in canvas space (RectTransfom /// /// public static Vector2 ToWorldPosition(this RectTransform transform, Camera camera = null) { var cam = camera; if (cam == null) cam = Camera.main; if (cam == null) return Vector2.zero; var pos = cam.ViewportToWorldPoint(transform.position); var worldPosition = cam.WorldToViewportPoint(pos); return worldPosition; } #region Position X Y Z public static void SetPosition(this Transform transform, in Vector3 v3) { transform.position = v3; } public static void SetPositionX(this Transform transform, float x) { var v3 = transform.position; v3.x = x; transform.position = v3; } public static void SetPositionY(this Transform transform, float y) { var v3 = transform.position; v3.y = y; transform.position = v3; } public static void SetPositionZ(this Transform transform, float z) { var v3 = transform.position; v3.z = z; transform.position = v3; } #endregion #region Position XY public static void SetPositionXY(this Transform transform, in Vector2 v2) { transform.position = new Vector3(v2.x, v2.y, transform.position.z); } public static void SetPositionXY(this Transform transform, float x, float y) { transform.position = new Vector3(x, y, transform.position.z); } public static void SetPositionXY(this Transform transform, Transform target) { var v3 = target.position; v3.z = transform.position.z; transform.position = v3; } #endregion #region Position XZ public static void GetPositionXZ(this Transform transform, out Vector2 v2) { var v3 = transform.position; v2.x = v3.x; v2.y = v3.z; } public static Vector2 GetPositionXZ(this Transform transform) { var v3 = transform.position; return new Vector2(v3.x, v3.z); } public static void SetPositionXZ(this Transform transform, in Vector2 v2) { transform.position = new Vector3(v2.x, transform.position.y, v2.y); } public static void SetPositionXZ(this Transform transform, float x, float z) { transform.position = new Vector3(x, transform.position.y, z); } public static void SetPositionXZ(this Transform transform, Transform target) { var v3 = target.position; v3.y = transform.position.y; transform.position = v3; } #endregion #region Position YZ public static void GetPositionYZ(this Transform transform, out Vector2 v2) { var v3 = transform.position; v2.x = v3.y; v2.y = v3.z; } public static Vector2 GetPositionYZ(this Transform transform) { var v3 = transform.position; return new Vector2(v3.y, v3.z); } public static void SetPositionYZ(this Transform transform, in Vector2 v2) { transform.position = new Vector3(transform.position.x, v2.x, v2.y); } public static void SetPositionYZ(this Transform transform, float y, float z) { transform.position = new Vector3(transform.position.x, y, z); } public static void SetPositionYZ(this Transform transform, Transform target) { var v3 = target.position; v3.x = transform.position.x; transform.position = v3; } #endregion #region Relative Position X Y Z public static void SetRelativePosition(this Transform transform, in Vector3 v3) { transform.position += v3; } public static void SetRelativePositionX(this Transform transform, float x) { var v3 = transform.position; v3.x += x; transform.position = v3; } public static void SetRelativePositionY(this Transform transform, float y) { var v3 = transform.position; v3.y += y; transform.position = v3; } public static void SetRelativePositionZ(this Transform transform, float z) { var v3 = transform.position; v3.z += z; transform.position = v3; } #endregion #region Relative Position XY public static void SetRelativePositionXY(this Transform transform, in Vector2 v2) { var v3 = transform.position; v3.x += v2.x; v3.y += v2.y; transform.position = v3; } public static void SetRelativePositionXY(this Transform transform, float x, float y) { var v3 = transform.position; v3.x += x; v3.y += y; transform.position = v3; } public static void SetRelativePositionXY(this Transform transform, Transform target) { var v3 = transform.position; var targetV3 = target.position; v3.x += targetV3.x; v3.y += targetV3.y; transform.position = v3; } #endregion #region Relative Position XZ public static void SetRelativePositionXZ(this Transform transform, in Vector2 v2) { var v3 = transform.position; v3.x += v2.x; v3.z += v2.y; transform.position = v3; } public static void SetRelativePositionXZ(this Transform transform, float x, float z) { var v3 = transform.position; v3.x += x; v3.z += z; transform.position = v3; } public static void SetRelativePositionXZ(this Transform transform, Transform target) { var v3 = transform.position; var targetV3 = target.position; v3.x += targetV3.x; v3.z += targetV3.z; transform.position = v3; } #endregion #region Relative Position YZ public static void SetRelativePositionYZ(this Transform transform, in Vector2 v2) { var v3 = transform.position; v3.y += v2.x; v3.z += v2.y; transform.position = v3; } public static void SetRelativePositionYZ(this Transform transform, float y, float z) { var v3 = transform.position; v3.y += y; v3.z += z; transform.position = v3; } public static void SetRelativePositionYZ(this Transform transform, Transform target) { var v3 = transform.position; var targetV3 = target.position; v3.y += targetV3.y; v3.z += targetV3.z; transform.position = v3; } #endregion #region Local Position X Y Z public static void SetLocalPositionX(this Transform transform, float x) { var v3 = transform.localPosition; v3.x = x; transform.localPosition = v3; } public static void SetLocalPositionY(this Transform transform, float y) { var v3 = transform.localPosition; v3.y = y; transform.localPosition = v3; } public static void SetLocalPositionZ(this Transform transform, float z) { var v3 = transform.localPosition; v3.z = z; transform.localPosition = v3; } #endregion #region Local Position XY public static void SetLocalPositionXY(this Transform transform, in Vector2 v2) { transform.localPosition = new Vector3(v2.x, v2.y, transform.localPosition.z); } public static void SetLocalPositionXY(this Transform transform, float x, float y) { transform.localPosition = new Vector3(x, y, transform.localPosition.z); } public static void SetLocalPositionXY(this Transform transform, Transform target) { var v3 = target.localPosition; v3.z = transform.localPosition.z; transform.localPosition = v3; } #endregion #region Local Position XZ public static void GetLocalPositionXZ(this Transform transform, out Vector2 v2) { var v3 = transform.localPosition; v2.x = v3.x; v2.y = v3.z; } public static Vector2 GetLocalPositionXZ(this Transform transform) { var v3 = transform.localPosition; return new Vector2(v3.x, v3.z); } public static void SetLocalPositionXZ(this Transform transform, in Vector2 v2) { transform.localPosition = new Vector3(v2.x, transform.localPosition.y, v2.y); } public static void SetLocalPositionXZ(this Transform transform, float x, float z) { transform.localPosition = new Vector3(x, transform.localPosition.y, z); } public static void SetLocalPositionXZ(this Transform transform, Transform target) { var v3 = target.localPosition; v3.y = transform.localPosition.y; transform.localPosition = v3; } #endregion #region Local Position YZ public static void GetLocalPositionYZ(this Transform transform, out Vector2 v2) { var v3 = transform.localPosition; v2.x = v3.y; v2.y = v3.z; } public static Vector2 GetLocalPositionYZ(this Transform transform) { var v3 = transform.localPosition; return new Vector2(v3.y, v3.z); } public static void SetLocalPositionYZ(this Transform transform, in Vector2 v2) { transform.localPosition = new Vector3(transform.localPosition.x, v2.x, v2.y); } public static void SetLocalPositionYZ(this Transform transform, float y, float z) { transform.localPosition = new Vector3(transform.localPosition.x, y, z); } public static void SetLocalPositionYZ(this Transform transform, Transform target) { var v3 = target.localPosition; v3.x = transform.localPosition.x; transform.localPosition = v3; } #endregion #region Relative Local Position X Y Z public static void SetRelativeLocalPositionX(this Transform transform, float x) { var v3 = transform.localPosition; v3.x += x; transform.localPosition = v3; } public static void SetRelativeLocalPositionY(this Transform transform, float y) { var v3 = transform.localPosition; v3.y += y; transform.localPosition = v3; } public static void SetRelativeLocalPositionZ(this Transform transform, float z) { var v3 = transform.localPosition; v3.z += z; transform.localPosition = v3; } #endregion #region Relative Local Position XY public static void SetRelativeLocalPositionXY(this Transform transform, in Vector2 v2) { var v3 = transform.localPosition; v3.x += v2.x; v3.y += v2.y; transform.localPosition = v3; } public static void SetRelativeLocalPositionXY(this Transform transform, float x, float y) { var v3 = transform.localPosition; v3.x += x; v3.y += y; transform.localPosition = v3; } public static void SetRelativeLocalPositionXY(this Transform transform, Transform target) { var v3 = transform.localPosition; var targetV3 = target.localPosition; v3.x += targetV3.x; v3.y += targetV3.y; transform.localPosition = v3; } #endregion #region Relative Local Position XZ public static void SetRelativeLocalPositionXZ(this Transform transform, in Vector2 v2) { var v3 = transform.localPosition; v3.x += v2.x; v3.z += v2.y; transform.localPosition = v3; } public static void SetRelativeLocalPositionXZ(this Transform transform, float x, float z) { var v3 = transform.localPosition; v3.x += x; v3.z += z; transform.localPosition = v3; } public static void SetRelativeLocalPositionXZ(this Transform transform, Transform target) { var v3 = transform.localPosition; var targetV3 = target.localPosition; v3.x += targetV3.x; v3.z += targetV3.z; transform.localPosition = v3; } #endregion #region Relative Local Postion YZ public static void SetRelativeLocalPositionYZ(this Transform transform, in Vector2 v2) { var v3 = transform.localPosition; v3.y += v2.x; v3.z += v2.y; transform.localPosition = v3; } public static void SetRelativeLocalPositionYZ(this Transform transform, float y, float z) { var v3 = transform.localPosition; v3.y += y; v3.z += z; transform.localPosition = v3; } public static void SetRelativeLocalPositionYZ(this Transform transform, Transform target) { var v3 = transform.localPosition; var targetV3 = target.localPosition; v3.y += targetV3.y; v3.z += targetV3.z; transform.localPosition = v3; } #endregion #region Scale X Y Z public static void SetScaleX(this Transform transform, float x) { var v3 = transform.localScale; v3.x = x; transform.localScale = v3; } public static void SetScaleY(this Transform transform, float y) { var v3 = transform.localScale; v3.y = y; transform.localScale = v3; } public static void SetScaleZ(this Transform transform, float z) { var v3 = transform.localScale; v3.z = z; transform.localScale = v3; } #endregion #region Scale XY public static void SetScaleXY(this Transform transform, in Vector2 v2) { transform.localScale = new Vector3(v2.x, v2.y, transform.localScale.z); } public static void SetScaleXY(this Transform transform, float x, float y) { transform.localScale = new Vector3(x, y, transform.localScale.z); } public static void SetScaleXY(this Transform transform, float value) { transform.localScale = new Vector3(value, value, transform.localScale.z); } public static void SetScaleXY(this Transform transform, Transform target) { var v3 = target.localScale; v3.z = transform.localScale.z; transform.localScale = v3; } #endregion #region Scale XZ public static void GetScaleXZ(this Transform transform, out Vector2 v2) { var v3 = transform.localScale; v2.x = v3.x; v2.y = v3.z; } public static Vector2 GetScaleXZ(this Transform transform) { var v3 = transform.localScale; return new Vector2(v3.x, v3.z); } public static void SetScaleXZ(this Transform transform, in Vector2 v2) { transform.localScale = new Vector3(v2.x, transform.localScale.y, v2.y); } public static void SetScaleXZ(this Transform transform, float x, float z) { transform.localScale = new Vector3(x, transform.localScale.y, z); } public static void SetScaleXZ(this Transform transform, float value) { transform.localScale = new Vector3(value, transform.localScale.y, value); } public static void SetScaleXZ(this Transform transform, Transform target) { var v3 = target.localScale; v3.y = transform.localScale.y; transform.localScale = v3; } #endregion #region Scale YZ public static void GetScaleYZ(this Transform transform, out Vector2 v2) { var v3 = transform.localScale; v2.x = v3.y; v2.y = v3.z; } public static Vector2 GetScaleYZ(this Transform transform) { var v3 = transform.localScale; return new Vector2(v3.y, v3.z); } public static void SetScaleYZ(this Transform transform, in Vector2 v2) { transform.localScale = new Vector3(transform.localScale.x, v2.x, v2.y); } public static void SetScaleYZ(this Transform transform, float y, float z) { transform.localScale = new Vector3(transform.localScale.x, y, z); } public static void SetScaleYZ(this Transform transform, float value) { transform.localScale = new Vector3(transform.localScale.x, value, value); } public static void SetScaleYZ(this Transform transform, Transform target) { var v3 = target.localScale; v3.x = transform.localScale.x; transform.localScale = v3; } #endregion #region Scale public static void SetScale(this Transform transform, float value) { transform.localScale = new Vector3(value, value, value); } #endregion #region Relative Scale X Y Z public static void SetRelativeScaleX(this Transform transform, float x) { var v3 = transform.localScale; v3.x += x; transform.localScale = v3; } public static void SetRelativeScaleY(this Transform transform, float y) { var v3 = transform.localScale; v3.y += y; transform.localScale = v3; } public static void SetRelativeScaleZ(this Transform transform, float z) { var v3 = transform.localScale; v3.z += z; transform.localScale = v3; } #endregion #region Relative Scale XY public static void SetRelativeScaleXY(this Transform transform, in Vector2 v2) { var v3 = transform.localScale; v3.x += v2.x; v3.y += v2.y; transform.localScale = v3; } public static void SetRelativeScaleXY(this Transform transform, float x, float y) { var v3 = transform.localScale; v3.x += x; v3.y += y; transform.localScale = v3; } public static void SetRelativeScaleXY(this Transform transform, float value) { var v3 = transform.localScale; v3.x += value; v3.y += value; transform.localScale = v3; } public static void SetRelativeScaleXY(this Transform transform, Transform target) { var v3 = transform.localScale; var targetV3 = target.localScale; v3.x += targetV3.x; v3.y += targetV3.y; transform.localScale = v3; } #endregion #region Relative Scale XZ public static void SetRelativeScaleXZ(this Transform transform, in Vector2 v2) { var v3 = transform.localScale; v3.x += v2.x; v3.z += v2.y; transform.localScale = v3; } public static void SetRelativeScaleXZ(this Transform transform, float x, float z) { var v3 = transform.localScale; v3.x += x; v3.z += z; transform.localScale = v3; } public static void SetRelativeScaleXZ(this Transform transform, float value) { var v3 = transform.localScale; v3.x += value; v3.z += value; transform.localScale = v3; } public static void SetRelativeScaleXZ(this Transform transform, Transform target) { var v3 = transform.localScale; var targetV3 = target.localScale; v3.x += targetV3.x; v3.z += targetV3.z; transform.localScale = v3; } #endregion #region Relative Scale YZ public static void SetRelativeScaleYZ(this Transform transform, in Vector2 v2) { var v3 = transform.localScale; v3.y += v2.x; v3.z += v2.y; transform.localScale = v3; } public static void SetRelativeScaleYZ(this Transform transform, float y, float z) { var v3 = transform.localScale; v3.y += y; v3.z += z; transform.localScale = v3; } public static void SetRelativeScaleYZ(this Transform transform, float value) { var v3 = transform.localScale; v3.y += value; v3.z += value; transform.localScale = v3; } public static void SetRelativeScaleYZ(this Transform transform, Transform target) { var v3 = transform.localScale; var targetV3 = target.localScale; v3.y += targetV3.y; v3.z += targetV3.z; transform.localScale = v3; } #endregion #region Relative Scale public static void SetRelativeScale(this Transform transform, float value) { transform.localScale += new Vector3(value, value, value); } #endregion #region Rotation X Y Z public static void SetRotationX(this Transform transform, float x) { var v3 = transform.eulerAngles; v3.x = x; transform.eulerAngles = v3; } public static void SetRotationY(this Transform transform, float y) { var v3 = transform.eulerAngles; v3.y = y; transform.eulerAngles = v3; } public static void SetRotationZ(this Transform transform, float z) { var v3 = transform.eulerAngles; v3.z = z; transform.eulerAngles = v3; } #endregion #region Rotation XY public static void SetRotationXY(this Transform transform, in Vector2 v2) { transform.eulerAngles = new Vector3(v2.x, v2.y, transform.eulerAngles.z); } public static void SetRotationXY(this Transform transform, float x, float y) { transform.eulerAngles = new Vector3(x, y, transform.eulerAngles.z); } public static void SetRotationXY(this Transform transform, Transform target) { var v3 = target.eulerAngles; v3.z = transform.eulerAngles.z; transform.eulerAngles = v3; } #endregion #region Rotation XZ public static void GetRotationXZ(this Transform transform, out Vector2 v2) { var v3 = transform.eulerAngles; v2.x = v3.x; v2.y = v3.z; } public static Vector2 GetRotationXZ(this Transform transform) { var v3 = transform.eulerAngles; return new Vector2(v3.x, v3.z); } public static void SetRotationXZ(this Transform transform, in Vector2 v2) { transform.eulerAngles = new Vector3(v2.x, transform.eulerAngles.y, v2.y); } public static void SetRotationXZ(this Transform transform, float x, float z) { transform.eulerAngles = new Vector3(x, transform.eulerAngles.y, z); } public static void SetRotationXZ(this Transform transform, Transform target) { var v3 = target.eulerAngles; v3.y = transform.eulerAngles.y; transform.eulerAngles = v3; } #endregion #region Rotation YZ public static void GetRotationYZ(this Transform transform, out Vector2 v2) { var v3 = transform.eulerAngles; v2.x = v3.y; v2.y = v3.z; } public static Vector2 GetRotationYZ(this Transform transform) { var v3 = transform.eulerAngles; return new Vector2(v3.y, v3.z); } public static void SetRotationYZ(this Transform transform, in Vector2 v2) { transform.eulerAngles = new Vector3(transform.eulerAngles.x, v2.x, v2.y); } public static void SetRotationYZ(this Transform transform, float y, float z) { transform.eulerAngles = new Vector3(transform.eulerAngles.x, y, z); } public static void SetRotationYZ(this Transform transform, Transform target) { var v3 = target.eulerAngles; v3.x = transform.eulerAngles.x; transform.eulerAngles = v3; } #endregion #region Relative Rotation X Y Z public static void SetRelativeRotationX(this Transform transform, float x) { var v3 = transform.eulerAngles; v3.x += x; transform.eulerAngles = v3; } public static void SetRelativeRotationY(this Transform transform, float y) { var v3 = transform.eulerAngles; v3.y += y; transform.eulerAngles = v3; } public static void SetRelativeRotationZ(this Transform transform, float z) { var v3 = transform.eulerAngles; v3.z += z; transform.eulerAngles = v3; } #endregion #region Relative Rotation XY public static void SetRelativeRotationXY(this Transform transform, in Vector2 v2) { var v3 = transform.eulerAngles; v3.x += v2.x; v3.y += v2.y; transform.eulerAngles = v3; } public static void SetRelativeRotationXY(this Transform transform, float x, float y) { var v3 = transform.eulerAngles; v3.x += x; v3.y += y; transform.eulerAngles = v3; } public static void SetRelativeRotationXY(this Transform transform, Transform target) { var v3 = transform.eulerAngles; var targetV3 = target.eulerAngles; v3.x += targetV3.x; v3.y += targetV3.y; transform.eulerAngles = v3; } #endregion #region Relative Rotation XZ public static void SetRelativeRotationXZ(this Transform transform, in Vector2 v2) { var v3 = transform.eulerAngles; v3.x += v2.x; v3.z += v2.y; transform.eulerAngles = v3; } public static void SetRelativeRotationXZ(this Transform transform, float x, float z) { var v3 = transform.eulerAngles; v3.x += x; v3.z += z; transform.eulerAngles = v3; } public static void SetRelativeRotationXZ(this Transform transform, Transform target) { var v3 = transform.eulerAngles; var targetV3 = target.eulerAngles; v3.x += targetV3.x; v3.z += targetV3.z; transform.eulerAngles = v3; } #endregion #region Relative Rotation YZ public static void SetRelativeRotationYZ(this Transform transform, in Vector2 v2) { var v3 = transform.eulerAngles; v3.y += v2.x; v3.z += v2.y; transform.eulerAngles = v3; } public static void SetRelativeRotationYZ(this Transform transform, float y, float z) { var v3 = transform.eulerAngles; v3.y += y; v3.z += z; transform.eulerAngles = v3; } public static void SetRelativeRotationYZ(this Transform transform, Transform target) { var v3 = transform.eulerAngles; var targetV3 = target.eulerAngles; v3.y += targetV3.y; v3.z += targetV3.z; transform.eulerAngles = v3; } #endregion #region Local Rotation X Y Z public static void SetLocalRotationX(this Transform transform, float x) { var v3 = transform.localEulerAngles; v3.x = x; transform.localEulerAngles = v3; } public static void SetLocalRotationY(this Transform transform, float y) { var v3 = transform.localEulerAngles; v3.y = y; transform.localEulerAngles = v3; } public static void SetLocalRotationZ(this Transform transform, float z) { var v3 = transform.localEulerAngles; v3.z = z; transform.localEulerAngles = v3; } #endregion #region Local Rotation XY public static void SetLocalRotationXY(this Transform transform, in Vector2 v2) { transform.localEulerAngles = new Vector3(v2.x, v2.y, transform.localEulerAngles.z); } public static void SetLocalRotationXY(this Transform transform, float x, float y) { transform.localEulerAngles = new Vector3(x, y, transform.localEulerAngles.z); } public static void SetLocalRotationXY(this Transform transform, Transform target) { var v3 = target.localEulerAngles; v3.z = transform.localEulerAngles.z; transform.localEulerAngles = v3; } #endregion #region Local Rotation XZ public static void GetLocalRotationXZ(this Transform transform, out Vector2 v2) { var v3 = transform.localEulerAngles; v2.x = v3.x; v2.y = v3.z; } public static Vector2 GetLocalRotationXZ(this Transform transform) { var v3 = transform.localEulerAngles; return new Vector2(v3.x, v3.z); } public static void SetLocalRotationXZ(this Transform transform, in Vector2 v2) { transform.localEulerAngles = new Vector3(v2.x, transform.localEulerAngles.y, v2.y); } public static void SetLocalRotationXZ(this Transform transform, float x, float z) { transform.localEulerAngles = new Vector3(x, transform.localEulerAngles.y, z); } public static void SetLocalRotationXZ(this Transform transform, Transform target) { var v3 = target.localEulerAngles; v3.y = transform.localEulerAngles.y; transform.localEulerAngles = v3; } #endregion #region Local Rotation YZ public static void GetLocalRotationYZ(this Transform transform, out Vector2 v2) { var v3 = transform.localEulerAngles; v2.x = v3.y; v2.y = v3.z; } public static Vector2 GetLocalRotationYZ(this Transform transform) { var v3 = transform.localEulerAngles; return new Vector2(v3.y, v3.z); } public static void SetLocalRotationYZ(this Transform transform, in Vector2 v2) { transform.localEulerAngles = new Vector3(transform.localEulerAngles.x, v2.x, v2.y); } public static void SetLocalRotationYZ(this Transform transform, float y, float z) { transform.localEulerAngles = new Vector3(transform.localEulerAngles.x, y, z); } public static void SetLocalRotationYZ(this Transform transform, Transform target) { var v3 = target.localEulerAngles; v3.x = transform.localEulerAngles.x; transform.localEulerAngles = v3; } #endregion #region Relative Local Rotation X Y Z public static void SetRelativeLocalRotationX(this Transform transform, float x) { var v3 = transform.localEulerAngles; v3.x += x; transform.localEulerAngles = v3; } public static void SetRelativeLocalRotationY(this Transform transform, float y) { var v3 = transform.localEulerAngles; v3.y += y; transform.localEulerAngles = v3; } public static void SetRelativeLocalRotationZ(this Transform transform, float z) { var v3 = transform.localEulerAngles; v3.z += z; transform.localEulerAngles = v3; } #endregion #region Relative Local Rotation XY public static void SetRelativeLocalRotationXY(this Transform transform, in Vector2 v2) { var v3 = transform.localEulerAngles; v3.x += v2.x; v3.y += v2.y; transform.localEulerAngles = v3; } public static void SetRelativeLocalRotationXY(this Transform transform, float x, float y) { var v3 = transform.localEulerAngles; v3.x += x; v3.y += y; transform.localEulerAngles = v3; } public static void SetRelativeLocalRotationXY(this Transform transform, Transform target) { var v3 = transform.localEulerAngles; var targetV3 = target.localEulerAngles; v3.x += targetV3.x; v3.y += targetV3.y; transform.localEulerAngles = v3; } #endregion #region Relative Local Rotation XZ public static void SetRelativeLocalRotationXZ(this Transform transform, in Vector2 v2) { var v3 = transform.localEulerAngles; v3.x += v2.x; v3.z += v2.y; transform.localEulerAngles = v3; } public static void SetRelativeLocalRotationXZ(this Transform transform, float x, float z) { var v3 = transform.localEulerAngles; v3.x += x; v3.z += z; transform.localEulerAngles = v3; } public static void SetRelativeLocalRotationXZ(this Transform transform, Transform target) { var v3 = transform.localEulerAngles; var targetV3 = target.localEulerAngles; v3.x += targetV3.x; v3.z += targetV3.z; transform.localEulerAngles = v3; } #endregion #region Relative Local Rotation YZ public static void SetRelativeLocalRotationYZ(this Transform transform, in Vector2 v2) { var v3 = transform.localEulerAngles; v3.y += v2.x; v3.z += v2.y; transform.localEulerAngles = v3; } public static void SetRelativeLocalRotationYZ(this Transform transform, float y, float z) { var v3 = transform.localEulerAngles; v3.y += y; v3.z += z; transform.localEulerAngles = v3; } public static void SetRelativeLocalRotationYZ(this Transform transform, Transform target) { var v3 = transform.localEulerAngles; var targetV3 = target.localEulerAngles; v3.y += targetV3.y; v3.z += targetV3.z; transform.localEulerAngles = v3; } #endregion #region Anchored Position X Y Z public static void SetAnchoredPositionX(this RectTransform rectTransform, float x) { var v2 = rectTransform.anchoredPosition; v2.x = x; rectTransform.anchoredPosition = v2; } public static void SetAnchoredPositionY(this RectTransform rectTransform, float y) { var v2 = rectTransform.anchoredPosition; v2.y = y; rectTransform.anchoredPosition = v2; } public static void SetAnchoredPositionZ(this RectTransform rectTransform, float z) { var v3 = rectTransform.anchoredPosition3D; v3.z = z; rectTransform.anchoredPosition3D = v3; } #endregion #region Relative Anchored Position X Y Z public static void SetRelativeAnchoredPositionX(this RectTransform rectTransform, float x) { var v2 = rectTransform.anchoredPosition; v2.x += x; rectTransform.anchoredPosition = v2; } public static void SetRelativeAnchoredPositionY(this RectTransform rectTransform, float y) { var v2 = rectTransform.anchoredPosition; v2.y += y; rectTransform.anchoredPosition = v2; } public static void SetRelativeAnchoredPositionZ(this RectTransform rectTransform, float z) { var v3 = rectTransform.anchoredPosition3D; v3.z += z; rectTransform.anchoredPosition3D = v3; } #endregion } } ================================================ FILE: VirtueSky/Misc/Common.Transform.cs.meta ================================================ fileFormatVersion: 2 guid: 76a24755436e4f4bb3ebb19dbf3a28b7 timeCreated: 1699240558 ================================================ FILE: VirtueSky/Misc/Common.cs ================================================ using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; using UnityEngine; using UnityEngine.Networking; using VirtueSky.Core; namespace VirtueSky.Misc { public static partial class Common { public static string Format(this string fmt, params object[] args) => string.Format(System.Globalization.CultureInfo.InvariantCulture.NumberFormat, fmt, args); public static bool IsInteger(this float value) { return (value == (int)value); } public static int GetNumberInAString(this string str) { try { var getNumb = Regex.Match(str, @"\d+").Value; return Int32.Parse(getNumb); } catch (Exception e) { return -1; } return -1; } public static float GetScreenRatio() { return (1920f / 1080f) / (Screen.height / (float)Screen.width); } public static void CallActionAndClean(ref Action action) { if (action == null) return; var a = action; a(); action = null; } public static void CallActionAndClean(ref Action action, T _value) { if (action == null) return; var a = action; a(_value); action = null; } #region Internet Connection private static IEnumerator internetConnectionCoroutine; public static void StopCheckInternetConnection() { App.StopCoroutine(internetConnectionCoroutine); } public static void CheckInternetConnection(Action actionConnected, Action actionDisconnected) { if (internetConnectionCoroutine != null) App.StopCoroutine(internetConnectionCoroutine); internetConnectionCoroutine = InternetConnection((isConnected) => { if (isConnected) { actionConnected?.Invoke(); } else { actionDisconnected?.Invoke(); } }); App.StartCoroutine(internetConnectionCoroutine); } public static IEnumerator InternetConnection(Action action) { bool result; string url = "https://google.com"; #if UNITY_ANDROID url = "https://google.com"; #elif UNITY_IOS url = "https://captive.apple.com/hotspot-detect.html"; #endif using (UnityWebRequest request = UnityWebRequest.Head(url)) { yield return request.SendWebRequest(); result = !request.isNetworkError && !request.isHttpError && request.responseCode == 200 && request.error == null; } action(result); internetConnectionCoroutine = null; } #endregion /// /// Attach a DelayHandle on to the behaviour. If the behaviour is destroyed before the DelayHandle is completed, /// e.g. through a scene change, the DelayHandle callback will not execute. /// /// The behaviour to attach this DelayHandle to. /// The duration to wait before the DelayHandle fires. /// The action to run when the DelayHandle elapses. /// A function to call each tick of the DelayHandle. Takes the number of seconds elapsed since /// the start of the current cycle. /// Whether the DelayHandle should restart after executing. /// Whether the DelayHandle uses real-time(not affected by slow-mo or pausing) or /// game-time(affected by time scale changes). public static DelayHandle Delay( this MonoBehaviour target, float duration, Action onComplete, Action onUpdate = null, bool isLooped = false, bool useRealTime = false) { return App.Delay( target, duration, onComplete, onUpdate, isLooped, useRealTime); } } } ================================================ FILE: VirtueSky/Misc/Common.cs.meta ================================================ fileFormatVersion: 2 guid: ca637e462d4f747ec846934b2a8e0cc9 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Misc/virtuesky.sunflower.misc.asmdef ================================================ { "name": "Virtuesky.Sunflower.Misc", "rootNamespace": "", "references": [ "GUID:acb3cac55c622ec459c8caadf707623a", "GUID:ce8c6e3f188ed064f933ef35b46bf8bd", "GUID:80ecb87cae9c44d19824e70ea7229748", "GUID:72d1fea872bd7a449bf3818f2b0a6708", "GUID:68765d262e2128e4ab49c983f3411946", "GUID:4c25c05f410a3a447a75c3b0909152ef", "GUID:c282fd4f3fc2c7540914e85842a013c7" ], "includePlatforms": [], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], "versionDefines": [], "noEngineReferences": false } ================================================ FILE: VirtueSky/Misc/virtuesky.sunflower.misc.asmdef.meta ================================================ fileFormatVersion: 2 guid: fca7ec166e04dc948b624a983315e2c9 AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Misc.meta ================================================ fileFormatVersion: 2 guid: 3231e9518727a4f5eb3ff88394428280 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Notifications/Editor/NotificationWindowEditor.cs ================================================ using UnityEditor; using VirtueSky.Notifications; using VirtueSky.UtilsEditor; public class NotificationWindowEditor : EditorWindow { // [MenuItem("Sunflower/Notification Channel")] public static void CreateNotificationChannel() { CreateAsset.CreateScriptableAssetsOnlyName("/Notifications", "notification_channel_data"); } } ================================================ FILE: VirtueSky/Notifications/Editor/NotificationWindowEditor.cs.meta ================================================ fileFormatVersion: 2 guid: 8680608c365dc4d7dbc7b5439e9d392d MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Notifications/Editor/Virtuesky.Sunflower.Notifications.Editor.asmdef ================================================ { "name": "Virtuesky.Sunflower.Notifications.Editor", "rootNamespace": "", "references": [ "GUID:3aa1a48b88c8fc84ab64d4acf89d0b4e", "GUID:c904f6d969e991d459a0843b71c22ec5" ], "includePlatforms": [ "Editor" ], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], "versionDefines": [], "noEngineReferences": false } ================================================ FILE: VirtueSky/Notifications/Editor/Virtuesky.Sunflower.Notifications.Editor.asmdef.meta ================================================ fileFormatVersion: 2 guid: 8bd745a7d8af04c528da60c6b56aa92a AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Notifications/Editor.meta ================================================ fileFormatVersion: 2 guid: 1049fc5fd097048aaa1e56f847aa8bad folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Notifications/Runtime/NotificationAndroid.cs ================================================ #if UNITY_ANDROID && VIRTUESKY_NOTIFICATION using System; using System.Collections.Generic; using Unity.Notifications.Android; namespace VirtueSky.Notifications { internal static class NotificationAndroid { private static readonly Dictionary ChannelRegistered = new Dictionary(); private static void RegisterNotificationChannel(string identifier, string name, string description) { ChannelRegistered.TryGetValue(identifier, out bool registered); if (registered) return; AndroidNotificationCenter.RegisterNotificationChannel(new AndroidNotificationChannel { Id = identifier, Name = name, Importance = Importance.High, Description = description }); ChannelRegistered.Add(identifier, true); } internal static void Schedule( string identifier, string title, string text, TimeSpan timeOffset, string largeIcon = null, string channelName = "Nova", string channelDescription = "Newsletter Announcement", string smallIcon = "icon_0", BigPictureStyle? bigPictureStyle = null, bool repeat = false) { RegisterNotificationChannel(identifier, channelName, channelDescription); var notification = new AndroidNotification() { Title = title, Text = text, FireTime = DateTime.Now + timeOffset, Group = identifier, GroupSummary = true, ShouldAutoCancel = true, BigPicture = bigPictureStyle, }; if (repeat) notification.RepeatInterval = timeOffset; if (largeIcon != null) notification.LargeIcon = largeIcon; if (smallIcon != null) notification.SmallIcon = smallIcon; AndroidNotificationCenter.SendNotification(notification, identifier); } internal static void ScheduleAtSpecificTime( string identifier, string title, string text, DateTime fireTime, string largeIcon = null, string channelName = "Nova", string channelDescription = "Newsletter Announcement", string smallIcon = "icon_0", BigPictureStyle? bigPictureStyle = null, bool repeat = false) { RegisterNotificationChannel(identifier, channelName, channelDescription); var now = DateTime.Now; var todayFireTime = new DateTime(now.Year, now.Month, now.Day, fireTime.Hour, fireTime.Minute, fireTime.Second); var adjustedFireTime = todayFireTime; if (adjustedFireTime <= now) { adjustedFireTime = adjustedFireTime.AddDays(1); } var timeOffset = adjustedFireTime - now; var notification = new AndroidNotification() { Title = title, Text = text, FireTime = DateTime.Now + timeOffset, Group = identifier, GroupSummary = true, ShouldAutoCancel = true, BigPicture = bigPictureStyle, }; if (repeat) { notification.RepeatInterval = TimeSpan.FromDays(1); } if (largeIcon != null) notification.LargeIcon = largeIcon; if (smallIcon != null) notification.SmallIcon = smallIcon; AndroidNotificationCenter.SendNotification(notification, identifier); } internal static void CancelAllScheduled() { AndroidNotificationCenter.CancelAllScheduledNotifications(); } } } #endif ================================================ FILE: VirtueSky/Notifications/Runtime/NotificationAndroid.cs.meta ================================================ fileFormatVersion: 2 guid: 402d514dcc42447fbe9cd6f03b6a5a12 timeCreated: 1698142005 ================================================ FILE: VirtueSky/Notifications/Runtime/NotificationConsole.cs ================================================ using System; namespace VirtueSky.Notifications { internal static class NotificationConsole { internal static void Send( string identifier, string title, string text, string largeIcon = null, string channelName = "Nova", string channelDescription = "Newsletter Announcement", string smallIcon = null, bool bigPicture = false, string namePicture = "") { Schedule(identifier, title, text, TimeSpan.FromMilliseconds(250), largeIcon, channelName, channelDescription, smallIcon, bigPicture, namePicture); } internal static void Schedule( string identifier, string title, string text, TimeSpan timeOffset, string largeIcon = null, string channelName = "Nova", string channelDescription = "Newsletter Announcement", string smallIcon = null, bool bigPicture = false, string namePicture = "", bool repeat = false) { if (string.IsNullOrEmpty(smallIcon)) smallIcon = "icon_0"; if (string.IsNullOrEmpty(largeIcon)) largeIcon = "icon_1"; #if UNITY_ANDROID && VIRTUESKY_NOTIFICATION Unity.Notifications.Android.BigPictureStyle? bigPictureStyle = null; if (bigPicture) { bigPictureStyle = new Unity.Notifications.Android.BigPictureStyle { Picture = namePicture, ContentTitle = title, ContentDescription = text }; } NotificationAndroid.Schedule(identifier, title, text, timeOffset, largeIcon, channelName, channelDescription, smallIcon, bigPictureStyle, repeat); #elif UNITY_IOS && VIRTUESKY_NOTIFICATION NotificationIOS.Schedule(identifier, title, "", text, timeOffset, repeat); #endif } internal static void ScheduleAtSpecificTime( string identifier, string title, string text, DateTime fireTime, string largeIcon = null, string channelName = "Nova", string channelDescription = "Newsletter Announcement", string smallIcon = null, bool bigPicture = false, string namePicture = "", bool repeat = false) { if (string.IsNullOrEmpty(smallIcon)) smallIcon = "icon_0"; if (string.IsNullOrEmpty(largeIcon)) largeIcon = "icon_1"; #if UNITY_ANDROID && VIRTUESKY_NOTIFICATION Unity.Notifications.Android.BigPictureStyle? bigPictureStyle = null; if (bigPicture) { bigPictureStyle = new Unity.Notifications.Android.BigPictureStyle { Picture = namePicture, ContentTitle = title, ContentDescription = text }; } NotificationAndroid.ScheduleAtSpecificTime(identifier, title, text, fireTime, largeIcon, channelName, channelDescription, smallIcon, bigPictureStyle, repeat); #elif UNITY_IOS && VIRTUESKY_NOTIFICATION NotificationIOS.ScheduleAtSpecificTime(identifier, title, "", text, fireTime, repeat); #endif } internal static void CancelAllScheduled() { #if UNITY_ANDROID && VIRTUESKY_NOTIFICATION NotificationAndroid.CancelAllScheduled(); #elif UNITY_IOS && VIRTUESKY_NOTIFICATION NotificationIOS.CancelAllScheduled(); #endif } internal static void ClearBadgeCounterIOS() { #if UNITY_IOS && VIRTUESKY_NOTIFICATION NotificationIOS.ClearBadgeCounter(); #endif } } } ================================================ FILE: VirtueSky/Notifications/Runtime/NotificationConsole.cs.meta ================================================ fileFormatVersion: 2 guid: ebbfadc057d94706bce96c38e1e36dc7 timeCreated: 1698144094 ================================================ FILE: VirtueSky/Notifications/Runtime/NotificationIOS.cs ================================================ #if UNITY_IOS && VIRTUESKY_NOTIFICATION using System; using System.Collections.Generic; using Unity.Notifications.iOS; using UnityEngine; using Cysharp.Threading.Tasks; namespace VirtueSky.Notifications { internal static class NotificationIOS { private static Dictionary channelRegistered = new Dictionary(); internal static async UniTask RequestAuthorization() { var authorizationOption = AuthorizationOption.Alert | AuthorizationOption.Badge | AuthorizationOption.Sound; using (var req = new AuthorizationRequest(authorizationOption, true)) { while (!req.IsFinished) { await UniTask.Yield(); } } } private static async UniTask RegisterNotificationChannel(string identifier, string title, string subtitle, string body, iOSNotificationTrigger trigger) { await RequestAuthorization(); if (new iOSNotificationSettings().AuthorizationStatus != AuthorizationStatus.Authorized) { Debug.LogError("IOSNotification non authorized for schedule notification"); } var unregistered = !channelRegistered.ContainsKey(identifier) || !channelRegistered[identifier]; if (unregistered) { var notification = new iOSNotification() { Identifier = identifier, Title = title, Body = body, Subtitle = subtitle, ShowInForeground = true, ForegroundPresentationOption = (PresentationOption.Alert | PresentationOption.Badge | PresentationOption.Sound), CategoryIdentifier = "category_a", ThreadIdentifier = "thread1", Trigger = trigger, }; try { iOSNotificationCenter.ScheduleNotification(notification); channelRegistered[identifier] = true; } catch (Exception e) { Debug.LogException(e); } } } internal static void Schedule(string identifier, string title, string subtitle, string text, TimeSpan fireTime, bool repeat) { var interval = fireTime; if (interval <= TimeSpan.Zero) interval = TimeSpan.FromSeconds(1); var timeTrigger = new iOSNotificationTimeIntervalTrigger { TimeInterval = interval, Repeats = repeat }; RegisterNotificationChannel(identifier, title, subtitle, text, timeTrigger).Forget(); } internal static void ScheduleAtSpecificTime(string identifier, string title, string subtitle, string text, DateTime fireTime, bool repeat) { var now = DateTime.Now; // Tạo thời gian fire cho hôm nay với giờ/phút/giây từ fireTime var todayFireTime = new DateTime(now.Year, now.Month, now.Day, fireTime.Hour, fireTime.Minute, fireTime.Second); // Nếu thời gian hôm nay đã qua, schedule cho ngày mai var adjustedFireTime = todayFireTime; if (adjustedFireTime <= now) { adjustedFireTime = adjustedFireTime.AddDays(1); } // Tính timeOffset từ bây giờ đến thời gian fire var timeOffset = adjustedFireTime - now; var interval = timeOffset; if (interval <= TimeSpan.Zero) interval = TimeSpan.FromSeconds(1); var timeTrigger = new iOSNotificationTimeIntervalTrigger { TimeInterval = interval, Repeats = repeat }; RegisterNotificationChannel(identifier, title, subtitle, text, timeTrigger).Forget(); } internal static void CancelAllScheduled() { iOSNotificationCenter.RemoveAllScheduledNotifications(); } internal static void ClearBadgeCounter() { iOSNotificationCenter.ApplicationBadge = 0; } } } #endif ================================================ FILE: VirtueSky/Notifications/Runtime/NotificationIOS.cs.meta ================================================ fileFormatVersion: 2 guid: d3654c229d59459fba1c774a7f4c361e timeCreated: 1698142156 ================================================ FILE: VirtueSky/Notifications/Runtime/NotificationPrepare.cs ================================================ using System.Collections; using System.Collections.Generic; using System.IO; using UnityEngine; using UnityEngine.Networking; using VirtueSky.Core; using VirtueSky.Inspector; namespace VirtueSky.Notifications { [EditorIcon("script_noti"), HideMonoScript] public class NotificationPrepare : BaseMono { [Space(20), SerializeField] private NotificationVariable[] notificationVariables; [SerializeField] private bool autoSchedule = true; [Header("Schedule On Quit/Pause")] [SerializeField] private bool scheduleOnQuit = true; [SerializeField] private NotificationVariable[] notificationOnQuitVariables; private void Start() { #if UNITY_ANDROID PermissionPostNotification(); if (Application.isMobilePlatform) { var strs = new List(); foreach (var variable in notificationVariables) { if (!variable.bigPicture) continue; if (!strs.Contains(variable.namePicture)) strs.Add(variable.namePicture); } foreach (var variable in notificationOnQuitVariables) { if (variable == null || !variable.bigPicture) continue; if (!strs.Contains(variable.namePicture)) strs.Add(variable.namePicture); } foreach (string s in strs) { App.StartCoroutine(PrepareImage(Application.persistentDataPath, s)); } } #endif CancelAllScheduledNotifications(); } private void OnApplicationPause(bool pauseStatus) { if (pauseStatus) { ScheduleOnQuit(); if (autoSchedule) AutoSchedule(); } else { CancelAllScheduledNotifications(); } } private void ScheduleOnQuit() { if (!scheduleOnQuit) return; if (!Application.isMobilePlatform) return; foreach (var notification in notificationOnQuitVariables) { if (notification != null) { notification.Schedule(); } } } private void CancelAllScheduledNotifications() { if (!Application.isMobilePlatform) return; NotificationConsole.CancelAllScheduled(); } #if UNITY_ANDROID private IEnumerator PrepareImage(string destDir, string filename) { string path = Path.Combine(destDir, filename); if (File.Exists(path)) yield break; using var uwr = UnityWebRequest.Get(Path.Combine(Application.streamingAssetsPath, filename)); yield return uwr.SendWebRequest(); File.WriteAllBytes(path, uwr.downloadHandler.data); } void PermissionPostNotification() { if (!UnityEngine.Android.Permission.HasUserAuthorizedPermission("android.permission.POST_NOTIFICATIONS")) { UnityEngine.Android.Permission.RequestUserPermission("android.permission.POST_NOTIFICATIONS"); } } #endif void AutoSchedule() { foreach (var notification in notificationVariables) { notification.Schedule(); } } } } ================================================ FILE: VirtueSky/Notifications/Runtime/NotificationPrepare.cs.meta ================================================ fileFormatVersion: 2 guid: c4cadfcc9c3540478d6f4e3511ffac6e MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 7e5f4750d7e998c40a41333bba35d8b8, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Notifications/Runtime/NotificationVariable.cs ================================================ using System; using System.IO; using UnityEngine; using VirtueSky.Inspector; using VirtueSky.Misc; using VirtueSky.Variables; namespace VirtueSky.Notifications { [CreateAssetMenu(fileName = "notification_channel_data.asset", menuName = "Sunflower/Notification Channel")] [EditorIcon("scriptable_notification")] public class NotificationVariable : ScriptableObject { [Serializable] public class NotificationData { public string title; public string message; public NotificationData(string title, string message) { this.title = title; this.message = message; } } public enum ScheduleMode { RelativeTime, // Schedule sau X phút từ thời điểm hiện tại SpecificTime // Schedule vào giờ cụ thể (ví dụ: 6h tối ngày mai) } [SerializeField] private string identifier; [SerializeField] private ScheduleMode scheduleMode = ScheduleMode.RelativeTime; // === Relative Time Settings === [ShowIf(nameof(scheduleMode), ScheduleMode.RelativeTime)] [SerializeField] private bool isRemoteConfigTimeSchedule; [ShowIf(nameof(isRemoteConfigTimeSchedule)), SerializeField] private IntegerVariable remoteConfigMinute; [HideIf(nameof(isRemoteConfigTimeSchedule))] [ShowIf(nameof(scheduleMode), ScheduleMode.RelativeTime)] public int minute; // === Specific Time Settings === [ShowIf(nameof(scheduleMode), ScheduleMode.SpecificTime)] [SerializeField, Range(0, 23)] private int targetHour = 18; // 6h tối [ShowIf(nameof(scheduleMode), ScheduleMode.SpecificTime)] [SerializeField, Range(0, 59)] private int targetMinute = 0; [SerializeField] private bool repeat; [SerializeField] internal bool bigPicture; [ShowIf(nameof(bigPicture))] #if UNITY_EDITOR [HelpBox( "File big picture must be place in folder StreamingAsset, Name Picture must contains file extension ex .jpg")] #endif [SerializeField] internal string namePicture; [SerializeField] internal bool overrideIcon; [SerializeField, ShowIf(nameof(overrideIcon))] internal string smallIcon = "icon_0"; [SerializeField, ShowIf(nameof(overrideIcon))] internal string largeIcon = "icon_1"; [SerializeField] private NotificationData[] datas; int GetMinute() { if (isRemoteConfigTimeSchedule) { return remoteConfigMinute.Value; } return minute; } DateTime? GetFireTime() { if (scheduleMode == ScheduleMode.SpecificTime) { var now = DateTime.Now; return new DateTime(now.Year, now.Month, now.Day, targetHour, targetMinute, 0); } return null; // RelativeTime mode không cần DateTime cụ thể } public void Send() { if (!Application.isMobilePlatform) return; var data = datas.PickRandom(); string pathPicture = Path.Combine(Application.persistentDataPath, namePicture); NotificationConsole.Send(identifier, data.title, data.message, smallIcon: smallIcon, largeIcon: largeIcon, bigPicture: bigPicture, namePicture: pathPicture); } public void Schedule() { if (!Application.isMobilePlatform) return; var data = datas.PickRandom(); string pathPicture = Path.Combine(Application.persistentDataPath, namePicture); if (scheduleMode == ScheduleMode.SpecificTime) { // Schedule vào giờ cụ thể var fireTime = GetFireTime(); if (fireTime.HasValue) { NotificationConsole.ScheduleAtSpecificTime(identifier, data.title, data.message, fireTime.Value, smallIcon: smallIcon, largeIcon: largeIcon, bigPicture: bigPicture, namePicture: pathPicture, repeat: repeat); // Repeat interval cố định 24h } } else { // Schedule theo khoảng thời gian tương đối (logic cũ) NotificationConsole.Schedule(identifier, data.title, data.message, TimeSpan.FromMinutes(GetMinute()), smallIcon: smallIcon, largeIcon: largeIcon, bigPicture: bigPicture, namePicture: pathPicture, repeat: repeat); } } /// /// Schedule notification with a custom delay time. /// Used for scheduling notifications after app quit. /// public void ScheduleWithDelay(TimeSpan delay) { if (!Application.isMobilePlatform) return; var data = datas.PickRandom(); string pathPicture = Path.Combine(Application.persistentDataPath, namePicture); NotificationConsole.Schedule(identifier, data.title, data.message, TimeSpan.FromMinutes(GetMinute()), smallIcon: smallIcon, largeIcon: largeIcon, bigPicture: bigPicture, namePicture: pathPicture, repeat: false); // Không repeat khi schedule từ quit app } public void CancelAllScheduled() { if (!Application.isMobilePlatform) return; NotificationConsole.CancelAllScheduled(); } public void ClearBadgeCounterIOS() { if (!Application.isMobilePlatform) return; NotificationConsole.ClearBadgeCounterIOS(); } } } ================================================ FILE: VirtueSky/Notifications/Runtime/NotificationVariable.cs.meta ================================================ fileFormatVersion: 2 guid: 4e085a2b84ef47babb9a940a1c0ead91 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 6a4b74d7042712c41acccbc6d90305fd, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Notifications/Runtime/virtuesky.sunflower.notifications.asmdef ================================================ { "name": "Virtuesky.Sunflower.Notifications", "rootNamespace": "Virtuesky.Notifications", "references": [ "GUID:ac145e6b8c6034cdbadc8c6e26aedbcf", "GUID:1e8e55397bd004beaba78a667566665f", "GUID:acb3cac55c622ec459c8caadf707623a", "GUID:fca7ec166e04dc948b624a983315e2c9", "GUID:f51ebe6a0ceec4240a699833d6309b23", "GUID:324caed91501a9c47a04ebfd87b68794", "GUID:35d694408290717499b3838802212c7f", "GUID:bd40169efe8642149b1d2b72ba4903ce" ], "includePlatforms": [], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], "versionDefines": [ { "name": "com.unity.mobile.notifications", "expression": "2.2.2", "define": "VIRTUESKY_NOTIFICATION" } ], "noEngineReferences": false } ================================================ FILE: VirtueSky/Notifications/Runtime/virtuesky.sunflower.notifications.asmdef.meta ================================================ fileFormatVersion: 2 guid: 3aa1a48b88c8fc84ab64d4acf89d0b4e AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Notifications/Runtime.meta ================================================ fileFormatVersion: 2 guid: 4f687231ff0264b3996f6b0b445b6299 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Notifications.meta ================================================ fileFormatVersion: 2 guid: 1e6ece33e35efd84180e34f52f349935 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/ObjectPooling/Pool.cs ================================================ using UnityEngine; namespace VirtueSky.ObjectPooling { public static class Pool { private static PoolHandle _poolHandle; public static void InitPool() { if (_poolHandle == null) { _poolHandle = new PoolHandle(); _poolHandle.Initialize(); } } #region API Spawn public static void PreSpawn(this PoolData poolData) { if (_poolHandle == null) { Debug.Log($"Please init pool before {System.Reflection.MethodBase.GetCurrentMethod()?.Name}"); return; } _poolHandle.PreSpawn(poolData); } public static GameObject Spawn(this GameObject prefab, Transform parent = null, bool worldPositionStays = true, bool initialize = true) { if (_poolHandle == null) { Debug.Log($"Please init pool before {System.Reflection.MethodBase.GetCurrentMethod()?.Name}"); return null; } return _poolHandle.Spawn(prefab, parent, worldPositionStays, initialize); } public static T Spawn(this T type, Transform parent = null, bool worldPositionStays = true, bool initialize = true) where T : Component { if (_poolHandle == null) { Debug.Log($"Please init pool before {System.Reflection.MethodBase.GetCurrentMethod()?.Name}"); return null; } return _poolHandle.Spawn(type, parent, worldPositionStays, initialize).GetComponent(); } public static GameObject Spawn(this GameObject prefab, Vector3 position, Quaternion rotation, Transform parent = null, bool worldPositionStays = true, bool initialize = true) { if (_poolHandle == null) { Debug.Log($"Please init pool before {System.Reflection.MethodBase.GetCurrentMethod()?.Name}"); return null; } return _poolHandle.Spawn(prefab, position, rotation, parent, worldPositionStays, initialize); } public static T Spawn(this T type, Vector3 position, Quaternion rotation, Transform parent = null, bool worldPositionStays = true, bool initialize = true) where T : Component { if (_poolHandle == null) { Debug.Log($"Please init pool before {System.Reflection.MethodBase.GetCurrentMethod()?.Name}"); return null; } return _poolHandle.Spawn(type, position, rotation, parent, worldPositionStays, initialize) .GetComponent(); } #endregion #region API DeSpawn public static void DeSpawn(this GameObject gameObject, bool destroy = false, bool worldPositionStays = true) { if (_poolHandle == null) { Debug.Log($"Please init pool before {System.Reflection.MethodBase.GetCurrentMethod()?.Name}"); return; } _poolHandle.DeSpawn(gameObject, destroy, worldPositionStays); } public static void DeSpawn(this T type, bool destroy = false, bool worldPositionStays = true) where T : Component { if (_poolHandle == null) { Debug.Log($"Please init pool before {System.Reflection.MethodBase.GetCurrentMethod()?.Name}"); return; } _poolHandle.DeSpawn(type, destroy, worldPositionStays); } public static void DeSpawnAll() { if (_poolHandle == null) { Debug.Log($"Please init pool before {System.Reflection.MethodBase.GetCurrentMethod()?.Name}"); return; } _poolHandle.DeSpawnAll(); } #endregion #region API Destroy public static void DestroyAll() { if (_poolHandle == null) { Debug.Log($"Please init pool before {System.Reflection.MethodBase.GetCurrentMethod()?.Name}"); return; } _poolHandle.DestroyAll(); } public static void DestroyAllWaitPools() { if (_poolHandle == null) { Debug.Log($"Please init pool before {System.Reflection.MethodBase.GetCurrentMethod()?.Name}"); return; } _poolHandle.DestroyAllWaitPools(); } #endregion } } ================================================ FILE: VirtueSky/ObjectPooling/Pool.cs.meta ================================================ fileFormatVersion: 2 guid: d45c7da498394701bdec5fc3d009c838 timeCreated: 1718288027 ================================================ FILE: VirtueSky/ObjectPooling/PoolData.cs ================================================ using System; using UnityEngine; namespace VirtueSky.ObjectPooling { [Serializable] public class PoolData { public GameObject prefab; public int count; } } ================================================ FILE: VirtueSky/ObjectPooling/PoolData.cs.meta ================================================ fileFormatVersion: 2 guid: 2f523271ec3745128123b017c75e5da1 timeCreated: 1718287843 ================================================ FILE: VirtueSky/ObjectPooling/PoolHandle.cs ================================================ using System.Collections.Generic; using System.Linq; using UnityEngine; using UnityEngine.SceneManagement; using VirtueSky.Core; #if UNITY_EDITOR #endif namespace VirtueSky.ObjectPooling { internal sealed class PoolHandle { private Dictionary> waitPool; private LinkedList activePool; private Transform container; private bool initialized; internal void Initialize() { if (initialized) return; initialized = true; waitPool = new Dictionary>(); activePool = new LinkedList(); container = new GameObject("PoolContainer").transform; UnityEngine.Object.DontDestroyOnLoad(container.gameObject); } internal void PreSpawn(PoolData poolData) { for (var i = 0; i < poolData.count; i++) { SpawnNew(poolData.prefab); } } private void SpawnNew(GameObject prefab) { var gameObject = UnityEngine.Object.Instantiate(prefab); var id = gameObject.AddComponent(); id.prefab = prefab; activePool.AddLast(gameObject); DeSpawn(gameObject, false); } internal void DeSpawn(T type, bool destroy = false, bool worldPositionStays = true) where T : Component { DeSpawn(type.gameObject, destroy, worldPositionStays); } internal void DeSpawn(GameObject gameObject, bool destroy = false, bool worldPositionStays = true) { var id = gameObject.GetComponent(); if (id == null) { Debug.LogError($"{gameObject.name} is not a pooled object!"); return; } if (!activePool.Contains(gameObject)) { Debug.LogError($"{gameObject.name} is not in active pool!"); return; } activePool.Remove(gameObject); if (!waitPool.ContainsKey(id.prefab)) { waitPool.Add(id.prefab, new Queue()); } var stack = waitPool[id.prefab]; if (stack.Contains(gameObject)) { Debug.LogError($"{gameObject.name} is already pooled!"); return; } CleanUp(gameObject); if (destroy) { UnityEngine.Object.Destroy(gameObject); } else { gameObject.SetActive(false); gameObject.transform.SetParent(container, worldPositionStays); stack.Enqueue(gameObject); } } internal void DeSpawnAll() { var arr = activePool.ToArray(); foreach (var o in arr) { if (o != null) DeSpawn(o); } } internal void DestroyAllWaitPools() { foreach (var (key, queue) in waitPool) { foreach (var go in queue) { CleanUp(go); UnityEngine.Object.DestroyImmediate(go); } queue.Clear(); } waitPool.Clear(); } internal void DestroyAll() { var arr = waitPool.Values.SelectMany(g => g).ToArray(); for (var i = 0; i < arr.Length; i++) { UnityEngine.Object.Destroy(arr[i].gameObject); } waitPool.Clear(); } internal T Spawn(T type, Transform parent = null, bool worldPositionStays = true, bool initialize = true) where T : Component { return Spawn(type.gameObject, parent, worldPositionStays, initialize).GetComponent(); } internal GameObject Spawn(GameObject prefab, Transform parent = null, bool worldPositionStays = true, bool initialize = true) { if (!waitPool.ContainsKey(prefab)) { waitPool.Add(prefab, new Queue()); } var stack = waitPool[prefab]; if (stack.Count == 0) { SpawnNew(prefab); } var gameObject = stack.Dequeue(); gameObject.transform.SetParent(parent, worldPositionStays); if (parent == null) { SceneManager.MoveGameObjectToScene(gameObject, SceneManager.GetActiveScene()); } gameObject.SetActive(true); if (initialize) { InitializeObj(gameObject); } activePool.AddLast(gameObject); return gameObject; } internal T Spawn(T type, Vector3 position, Quaternion rotation, Transform parent = null, bool worldPositionStays = true, bool initialize = true) where T : Component { return Spawn(type.gameObject, position, rotation, parent, worldPositionStays, initialize).GetComponent(); } internal GameObject Spawn(GameObject prefab, Vector3 position, Quaternion rotation, Transform parent = null, bool worldPositionStays = true, bool initialize = true) { if (!waitPool.ContainsKey(prefab)) { waitPool.Add(prefab, new Queue()); } var stack = waitPool[prefab]; if (stack.Count == 0) { SpawnNew(prefab); } var gameObject = stack.Dequeue(); gameObject.transform.SetParent(parent, worldPositionStays); gameObject.transform.SetPositionAndRotation(position, rotation); if (parent == null) { SceneManager.MoveGameObjectToScene(gameObject, SceneManager.GetActiveScene()); } gameObject.SetActive(true); if (initialize) { InitializeObj(gameObject); } activePool.AddLast(gameObject); return gameObject; } void InitializeObj(GameObject go) { var monos = go.GetComponentsInChildren(true); foreach (var mono in monos) { mono.Initialize(); } } void CleanUp(GameObject go) { var monos = go.GetComponentsInChildren(true); foreach (var mono in monos) { mono.CleanUp(); } } } } ================================================ FILE: VirtueSky/ObjectPooling/PoolHandle.cs.meta ================================================ fileFormatVersion: 2 guid: ea56204fcdc152d4ba795117fd8fff72 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 9a1531ff57a958c4c92ab33ca22f62ef, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/ObjectPooling/PooledObjectId.cs ================================================ using UnityEngine; namespace VirtueSky.ObjectPooling { public class PooledObjectId : MonoBehaviour { public GameObject prefab; } } ================================================ FILE: VirtueSky/ObjectPooling/PooledObjectId.cs.meta ================================================ fileFormatVersion: 2 guid: b5e68b9f9e9f478ab34ddf8bcde5baa3 timeCreated: 1652323347 ================================================ FILE: VirtueSky/ObjectPooling/virtuesky.sunflower.objectpooling.asmdef ================================================ { "name": "Virtuesky.Sunflower.ObjectPooling", "rootNamespace": "", "references": [ "GUID:acb3cac55c622ec459c8caadf707623a", "GUID:c904f6d969e991d459a0843b71c22ec5", "GUID:324caed91501a9c47a04ebfd87b68794" ], "includePlatforms": [], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], "versionDefines": [], "noEngineReferences": false } ================================================ FILE: VirtueSky/ObjectPooling/virtuesky.sunflower.objectpooling.asmdef.meta ================================================ fileFormatVersion: 2 guid: ce8c6e3f188ed064f933ef35b46bf8bd AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/ObjectPooling.meta ================================================ fileFormatVersion: 2 guid: e935857045c5c7949b038f6337c22b52 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Rating/Editor/RatingWindowEditor.cs ================================================ using UnityEditor; namespace VirtueSky.Rating { #if UNITY_EDITOR using VirtueSky.UtilsEditor; public class RatingWindowEditor : EditorWindow { #region In App Review // [MenuItem("Sunflower/InAppReview")] public static void CreateInAppReview() { CreateAsset.CreateScriptableAssets("/InAppReview", "in_app_review"); } #endregion } #endif } ================================================ FILE: VirtueSky/Rating/Editor/RatingWindowEditor.cs.meta ================================================ fileFormatVersion: 2 guid: 9f3b777987e806743974099f2e64644d MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Rating/Editor/Virtuesky.Sunflower.Rating.Editor.asmdef ================================================ { "name": "Virtuesky.Sunflower.Rating.Editor", "rootNamespace": "", "references": [ "GUID:c1d20589f66abf146ba53fb06bf1e096", "GUID:c904f6d969e991d459a0843b71c22ec5" ], "includePlatforms": [ "Editor" ], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], "versionDefines": [], "noEngineReferences": false } ================================================ FILE: VirtueSky/Rating/Editor/Virtuesky.Sunflower.Rating.Editor.asmdef.meta ================================================ fileFormatVersion: 2 guid: 2e2b9634fb53a4c01af8453caa52e1b4 AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Rating/Editor.meta ================================================ fileFormatVersion: 2 guid: 0f33de8e4e83ea6448fd8cda07165391 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Rating/Runtime/InAppReview.cs ================================================ using VirtueSky.Inspector; namespace VirtueSky.Rating { using UnityEngine; using System.Collections; using VirtueSky.Core; #if UNITY_IOS using UnityEngine.iOS; #elif UNITY_ANDROID && VIRTUESKY_RATING using Google.Play.Review; #endif [CreateAssetMenu(menuName = "Sunflower/InAppReview", fileName = "in_app_review")] [EditorIcon("icon_scriptable")] public class InAppReview : ScriptableObject { #if UNITY_ANDROID && VIRTUESKY_RATING private ReviewManager _reviewManager; private PlayReviewInfo _playReviewInfo; private Coroutine _coroutine; #endif public void InitInAppReview() { if (!Application.isMobilePlatform) return; #if UNITY_ANDROID && VIRTUESKY_RATING _coroutine = App.StartCoroutine(InitReview()); #endif } public void RateAndReview() { if (!Application.isMobilePlatform) return; #if UNITY_ANDROID && VIRTUESKY_RATING App.StartCoroutine(LaunchReview()); #elif UNITY_IOS Device.RequestStoreReview(); #endif } #if UNITY_ANDROID && VIRTUESKY_RATING private IEnumerator InitReview(bool force = false) { if (_reviewManager == null) _reviewManager = new ReviewManager(); var requestFlowOperation = _reviewManager.RequestReviewFlow(); yield return requestFlowOperation; if (requestFlowOperation.Error != ReviewErrorCode.NoError) { if (force) DirectlyOpen(); yield break; } _playReviewInfo = requestFlowOperation.GetResult(); } public IEnumerator LaunchReview() { if (_playReviewInfo == null) { if (_coroutine != null) App.StopCoroutine(_coroutine); yield return App.StartCoroutine(InitReview(true)); } var launchFlowOperation = _reviewManager.LaunchReviewFlow(_playReviewInfo); yield return launchFlowOperation; _playReviewInfo = null; if (launchFlowOperation.Error != ReviewErrorCode.NoError) { DirectlyOpen(); yield break; } } #endif private void DirectlyOpen() { Application.OpenURL($"https://play.google.com/store/apps/details?id={Application.identifier}"); } } } ================================================ FILE: VirtueSky/Rating/Runtime/InAppReview.cs.meta ================================================ fileFormatVersion: 2 guid: 538a395c127744f089e6bdf4a887a5f6 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: ed5ec0bb4ec55df47af0ecc2bd7be5f9, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Rating/Runtime/virtuesky.sunflower.rating.asmdef ================================================ { "name": "Virtuesky.Sunflower.Rating", "rootNamespace": "", "references": [ "GUID:b4318b6f3695442c4983c360248781db", "GUID:4139e191aa32f459e9eb2e331225ad7e", "GUID:acb3cac55c622ec459c8caadf707623a", "GUID:324caed91501a9c47a04ebfd87b68794" ], "includePlatforms": [], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], "versionDefines": [], "noEngineReferences": false } ================================================ FILE: VirtueSky/Rating/Runtime/virtuesky.sunflower.rating.asmdef.meta ================================================ fileFormatVersion: 2 guid: c1d20589f66abf146ba53fb06bf1e096 AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Rating/Runtime.meta ================================================ fileFormatVersion: 2 guid: f9571eb1f2a824d9faed01d3af64a55b folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Rating.meta ================================================ fileFormatVersion: 2 guid: bfa984a0102e4ea5992ae004bda255e8 timeCreated: 1697010252 ================================================ FILE: VirtueSky/RemoteConfig/FirebaseRemoteConfigData.cs ================================================ using System; #if VIRTUESKY_FIREBASE_REMOTECONFIG using Firebase.RemoteConfig; #endif using UnityEngine; using VirtueSky.Inspector; using VirtueSky.Misc; using VirtueSky.Variables; namespace VirtueSky.RemoteConfigs { [Serializable] public class FirebaseRemoteConfigData { public string key; public TypeRemoteConfigData typeRemoteConfigData; [ShowIf(nameof(typeRemoteConfigData), TypeRemoteConfigData.StringData)] public StringVariable stringValue; [GUIColor(0.8f, 1.0f, 0.6f)] [ShowIf(nameof(typeRemoteConfigData), TypeRemoteConfigData.StringData)] [ReadOnly] public string resultStringValue; [ShowIf(nameof(typeRemoteConfigData), TypeRemoteConfigData.BooleanData)] public BooleanVariable boolValue; [GUIColor(0.8f, 1.0f, 0.6f)] [ShowIf(nameof(typeRemoteConfigData), TypeRemoteConfigData.BooleanData)] [ReadOnly] public bool resultBoolValue; [ShowIf(nameof(typeRemoteConfigData), TypeRemoteConfigData.IntData)] public IntegerVariable intValue; [GUIColor(0.8f, 1.0f, 0.6f)] [ShowIf(nameof(typeRemoteConfigData), TypeRemoteConfigData.IntData)] [ReadOnly] public int resultIntValue; #if VIRTUESKY_FIREBASE_REMOTECONFIG public void SetUpData(ConfigValue result) { switch (typeRemoteConfigData) { case TypeRemoteConfigData.StringData: if (result.Source == ValueSource.RemoteValue) { stringValue.Value = result.StringValue; } resultStringValue = stringValue.Value; Debug.Log($"{key}: {resultStringValue}".SetColor(Color.green)); break; case TypeRemoteConfigData.BooleanData: if (result.Source == ValueSource.RemoteValue) { boolValue.Value = result.BooleanValue; } resultBoolValue = boolValue.Value; Debug.Log($"{key}: {resultBoolValue}".SetColor(Color.green)); break; case TypeRemoteConfigData.IntData: if (result.Source == ValueSource.RemoteValue) { intValue.Value = int.Parse(result.StringValue); } resultIntValue = intValue.Value; Debug.Log($"{key}: {resultIntValue}".SetColor(Color.green)); break; } } #endif } public enum TypeRemoteConfigData { StringData, BooleanData, IntData } } ================================================ FILE: VirtueSky/RemoteConfig/FirebaseRemoteConfigData.cs.meta ================================================ fileFormatVersion: 2 guid: bf53a27a63001b44cbf10dab99ed8d4c MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/RemoteConfig/FirebaseRemoteConfigManager.cs ================================================ using System; using System.Collections.Generic; using System.Threading.Tasks; #if VIRTUESKY_FIREBASE using Firebase; using Firebase.Extensions; #endif #if VIRTUESKY_FIREBASE_REMOTECONFIG using Firebase.RemoteConfig; #endif using UnityEngine; using VirtueSky.Inspector; using VirtueSky.Misc; using VirtueSky.Utils; using VirtueSky.Variables; namespace VirtueSky.RemoteConfigs { [EditorIcon("icon_controller"), HideMonoScript] public class FirebaseRemoteConfigManager : MonoBehaviour { [SerializeField] private TypeInitRemoteConfig typeInitRemoteConfig; #if VIRTUESKY_FIREBASE [Space, ReadOnly, SerializeField] private DependencyStatus dependencyStatus = DependencyStatus.UnavailableOther; #endif [Space, SerializeField] private BooleanVariable isFetchRemoteConfigCompleted; [Space, SerializeField] private BooleanVariable firebaseDependencyAvailable; [Space, SerializeField] private FirebaseRemoteConfigData[] listRemoteConfigData; private void Awake() { if (typeInitRemoteConfig == TypeInitRemoteConfig.InitOnAwake) { InitRemoteConfig(); } } private void Start() { if (typeInitRemoteConfig == TypeInitRemoteConfig.InitOnStart) { InitRemoteConfig(); } } private void InitRemoteConfig() { #if VIRTUESKY_FIREBASE if (isFetchRemoteConfigCompleted != null) { isFetchRemoteConfigCompleted.Value = false; } if (firebaseDependencyAvailable != null) { firebaseDependencyAvailable.Value = false; } FirebaseApp.CheckAndFixDependenciesAsync().ContinueWithOnMainThread(task => { dependencyStatus = task.Result; if (dependencyStatus == DependencyStatus.Available) { var app = FirebaseApp.DefaultInstance; if (firebaseDependencyAvailable != null) { firebaseDependencyAvailable.Value = true; } #if VIRTUESKY_FIREBASE_REMOTECONFIG FetchDataAsync(); #endif } else { Debug.LogError($"Could not resolve all Firebase dependencies: {dependencyStatus}".SetColor(Color.red)); } }); #endif } #if VIRTUESKY_FIREBASE_REMOTECONFIG && VIRTUESKY_FIREBASE public Task FetchDataAsync() { Debug.Log("Fetching data...".SetColor(CustomColor.Cyan)); Task fetchTask = FirebaseRemoteConfig.DefaultInstance .FetchAsync(TimeSpan.Zero); return fetchTask.ContinueWithOnMainThread(tast => { var info = FirebaseRemoteConfig.DefaultInstance.Info; if (info.LastFetchStatus == LastFetchStatus.Success) { FirebaseRemoteConfig.DefaultInstance.ActivateAsync().ContinueWithOnMainThread( task => { Debug.Log(String.Format("Remote data loaded and ready (last fetch time {0}).".SetColor(CustomColor.Cyan), info.FetchTime)); foreach (var rmcData in listRemoteConfigData) { if (string.IsNullOrEmpty(rmcData.key) || (rmcData.typeRemoteConfigData == TypeRemoteConfigData.BooleanData && rmcData.boolValue == null) || (rmcData.typeRemoteConfigData == TypeRemoteConfigData.StringData && rmcData.stringValue == null) || (rmcData.typeRemoteConfigData == TypeRemoteConfigData.IntData && rmcData.intValue == null)) continue; rmcData.SetUpData(FirebaseRemoteConfig.DefaultInstance .GetValue(rmcData.key)); } if (isFetchRemoteConfigCompleted != null) { isFetchRemoteConfigCompleted.Value = true; } }); Debug.Log("Firebase Remote Config Fetching completed!".SetColor(Color.green)); } else { Debug.Log("Fetching data did not completed!".SetColor(Color.red)); } }); } #endif } enum TypeInitRemoteConfig { InitOnAwake, InitOnStart } } ================================================ FILE: VirtueSky/RemoteConfig/FirebaseRemoteConfigManager.cs.meta ================================================ fileFormatVersion: 2 guid: e909f45ff43f51f4eafa07ac90416b0b MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 1c63e3b6583d6b54a8de6efcd2a86725, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/RemoteConfig/Virtuesky.Sunflower.RemoteConfigs.asmdef ================================================ { "name": "Virtuesky.Sunflower.RemoteConfigs", "rootNamespace": "", "references": [ "GUID:acb3cac55c622ec459c8caadf707623a", "GUID:324caed91501a9c47a04ebfd87b68794", "GUID:bd40169efe8642149b1d2b72ba4903ce", "GUID:35d694408290717499b3838802212c7f", "GUID:fca7ec166e04dc948b624a983315e2c9", "GUID:c282fd4f3fc2c7540914e85842a013c7" ], "includePlatforms": [], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], "versionDefines": [], "noEngineReferences": false } ================================================ FILE: VirtueSky/RemoteConfig/Virtuesky.Sunflower.RemoteConfigs.asmdef.meta ================================================ fileFormatVersion: 2 guid: 8825d2918c76a804eb16e58185f7e6d3 AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/RemoteConfig.meta ================================================ fileFormatVersion: 2 guid: 77ac67b0da2cc6d4dbf0b969a97276ec folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/SimpleJSON/SimpleJSON.cs ================================================ /* * * * * * A simple JSON Parser / builder * ------------------------------ * * It mainly has been written as a simple JSON parser. It can build a JSON string * from the node-tree, or generate a node tree from any valid JSON string. * * Written by Bunny83 * 2012-06-09 * * Changelog now external. See Changelog.txt * * The MIT License (MIT) * * Copyright (c) 2012-2022 Markus Göbel (Bunny83) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * * */ using System; using System.Collections; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Text; namespace VirtueSky.SimpleJSON { public enum JSONNodeType { Array = 1, Object = 2, String = 3, Number = 4, NullValue = 5, Boolean = 6, None = 7, Custom = 0xFF, } public enum JSONTextMode { Compact, Indent } public abstract partial class JSONNode { #region Enumerators public struct Enumerator { private enum Type { None, Array, Object } private Type type; private Dictionary.Enumerator m_Object; private List.Enumerator m_Array; public bool IsValid { get { return type != Type.None; } } public Enumerator(List.Enumerator aArrayEnum) { type = Type.Array; m_Object = default(Dictionary.Enumerator); m_Array = aArrayEnum; } public Enumerator(Dictionary.Enumerator aDictEnum) { type = Type.Object; m_Object = aDictEnum; m_Array = default(List.Enumerator); } public KeyValuePair Current { get { if (type == Type.Array) return new KeyValuePair(string.Empty, m_Array.Current); else if (type == Type.Object) return m_Object.Current; return new KeyValuePair(string.Empty, null); } } public bool MoveNext() { if (type == Type.Array) return m_Array.MoveNext(); else if (type == Type.Object) return m_Object.MoveNext(); return false; } } public struct ValueEnumerator { private Enumerator m_Enumerator; public ValueEnumerator(List.Enumerator aArrayEnum) : this( new Enumerator(aArrayEnum)) { } public ValueEnumerator(Dictionary.Enumerator aDictEnum) : this( new Enumerator(aDictEnum)) { } public ValueEnumerator(Enumerator aEnumerator) { m_Enumerator = aEnumerator; } public JSONNode Current { get { return m_Enumerator.Current.Value; } } public bool MoveNext() { return m_Enumerator.MoveNext(); } public ValueEnumerator GetEnumerator() { return this; } } public struct KeyEnumerator { private Enumerator m_Enumerator; public KeyEnumerator(List.Enumerator aArrayEnum) : this( new Enumerator(aArrayEnum)) { } public KeyEnumerator(Dictionary.Enumerator aDictEnum) : this( new Enumerator(aDictEnum)) { } public KeyEnumerator(Enumerator aEnumerator) { m_Enumerator = aEnumerator; } public string Current { get { return m_Enumerator.Current.Key; } } public bool MoveNext() { return m_Enumerator.MoveNext(); } public KeyEnumerator GetEnumerator() { return this; } } public class LinqEnumerator : IEnumerator>, IEnumerable> { private JSONNode m_Node; private Enumerator m_Enumerator; internal LinqEnumerator(JSONNode aNode) { m_Node = aNode; if (m_Node != null) m_Enumerator = m_Node.GetEnumerator(); } public KeyValuePair Current { get { return m_Enumerator.Current; } } object IEnumerator.Current { get { return m_Enumerator.Current; } } public bool MoveNext() { return m_Enumerator.MoveNext(); } public void Dispose() { m_Node = null; m_Enumerator = new Enumerator(); } public IEnumerator> GetEnumerator() { return new LinqEnumerator(m_Node); } public void Reset() { if (m_Node != null) m_Enumerator = m_Node.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return new LinqEnumerator(m_Node); } } #endregion Enumerators #region common interface public static bool forceASCII = false; // Use Unicode by default public static bool longAsString = false; // lazy creator creates a JSONString instead of JSONNumber public static bool allowLineComments = true; // allow "//"-style comments at the end of a line public abstract JSONNodeType Tag { get; } public virtual JSONNode this[int aIndex] { get { return null; } set { } } public virtual JSONNode this[string aKey] { get { return null; } set { } } public virtual string Value { get { return ""; } set { } } public virtual int Count { get { return 0; } } public virtual bool IsNumber { get { return false; } } public virtual bool IsString { get { return false; } } public virtual bool IsBoolean { get { return false; } } public virtual bool IsNull { get { return false; } } public virtual bool IsArray { get { return false; } } public virtual bool IsObject { get { return false; } } public virtual bool Inline { get { return false; } set { } } public virtual void Add(string aKey, JSONNode aItem) { } public virtual void Add(JSONNode aItem) { Add("", aItem); } public virtual JSONNode Remove(string aKey) { return null; } public virtual JSONNode Remove(int aIndex) { return null; } public virtual JSONNode Remove(JSONNode aNode) { return aNode; } public virtual void Clear() { } public virtual JSONNode Clone() { return null; } public virtual IEnumerable Children { get { yield break; } } public IEnumerable DeepChildren { get { foreach (var C in Children) foreach (var D in C.DeepChildren) yield return D; } } public virtual bool HasKey(string aKey) { return false; } public virtual JSONNode GetValueOrDefault(string aKey, JSONNode aDefault) { return aDefault; } public override string ToString() { StringBuilder sb = new StringBuilder(); WriteToStringBuilder(sb, 0, 0, JSONTextMode.Compact); return sb.ToString(); } public virtual string ToString(int aIndent) { StringBuilder sb = new StringBuilder(); WriteToStringBuilder(sb, 0, aIndent, JSONTextMode.Indent); return sb.ToString(); } internal abstract void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode); public abstract Enumerator GetEnumerator(); public IEnumerable> Linq { get { return new LinqEnumerator(this); } } public KeyEnumerator Keys { get { return new KeyEnumerator(GetEnumerator()); } } public ValueEnumerator Values { get { return new ValueEnumerator(GetEnumerator()); } } #endregion common interface #region typecasting properties public virtual double AsDouble { get { double v = 0.0; if (double.TryParse(Value, NumberStyles.Float, CultureInfo.InvariantCulture, out v)) return v; return 0.0; } set { Value = value.ToString(CultureInfo.InvariantCulture); } } public virtual int AsInt { get { return (int)AsDouble; } set { AsDouble = value; } } public virtual float AsFloat { get { return (float)AsDouble; } set { AsDouble = value; } } public virtual bool AsBool { get { bool v = false; if (bool.TryParse(Value, out v)) return v; return !string.IsNullOrEmpty(Value); } set { Value = (value) ? "true" : "false"; } } public virtual long AsLong { get { long val = 0; if (long.TryParse(Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out val)) return val; return 0L; } set { Value = value.ToString(CultureInfo.InvariantCulture); } } public virtual ulong AsULong { get { ulong val = 0; if (ulong.TryParse(Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out val)) return val; return 0; } set { Value = value.ToString(CultureInfo.InvariantCulture); } } public virtual JSONArray AsArray { get { return this as JSONArray; } } public virtual JSONObject AsObject { get { return this as JSONObject; } } #endregion typecasting properties #region operators public static implicit operator JSONNode(string s) { return (s == null) ? (JSONNode)JSONNull.CreateOrGet() : new JSONString(s); } public static implicit operator string(JSONNode d) { return (d == null) ? null : d.Value; } public static implicit operator JSONNode(double n) { return new JSONNumber(n); } public static implicit operator double(JSONNode d) { return (d == null) ? 0 : d.AsDouble; } public static implicit operator JSONNode(float n) { return new JSONNumber(n); } public static implicit operator float(JSONNode d) { return (d == null) ? 0 : d.AsFloat; } public static implicit operator JSONNode(int n) { return new JSONNumber(n); } public static implicit operator int(JSONNode d) { return (d == null) ? 0 : d.AsInt; } public static implicit operator JSONNode(long n) { if (longAsString) return new JSONString(n.ToString(CultureInfo.InvariantCulture)); return new JSONNumber(n); } public static implicit operator long(JSONNode d) { return (d == null) ? 0L : d.AsLong; } public static implicit operator JSONNode(ulong n) { if (longAsString) return new JSONString(n.ToString(CultureInfo.InvariantCulture)); return new JSONNumber(n); } public static implicit operator ulong(JSONNode d) { return (d == null) ? 0 : d.AsULong; } public static implicit operator JSONNode(bool b) { return new JSONBool(b); } public static implicit operator bool(JSONNode d) { return (d == null) ? false : d.AsBool; } public static implicit operator JSONNode(KeyValuePair aKeyValue) { return aKeyValue.Value; } public static bool operator ==(JSONNode a, object b) { if (ReferenceEquals(a, b)) return true; bool aIsNull = a is JSONNull || ReferenceEquals(a, null) || a is JSONLazyCreator; bool bIsNull = b is JSONNull || ReferenceEquals(b, null) || b is JSONLazyCreator; if (aIsNull && bIsNull) return true; return !aIsNull && a.Equals(b); } public static bool operator !=(JSONNode a, object b) { return !(a == b); } public override bool Equals(object obj) { return ReferenceEquals(this, obj); } public override int GetHashCode() { return base.GetHashCode(); } #endregion operators [ThreadStatic] private static StringBuilder m_EscapeBuilder; internal static StringBuilder EscapeBuilder { get { if (m_EscapeBuilder == null) m_EscapeBuilder = new StringBuilder(); return m_EscapeBuilder; } } internal static string Escape(string aText) { var sb = EscapeBuilder; sb.Length = 0; if (sb.Capacity < aText.Length + aText.Length / 10) sb.Capacity = aText.Length + aText.Length / 10; foreach (char c in aText) { switch (c) { case '\\': sb.Append("\\\\"); break; case '\"': sb.Append("\\\""); break; case '\n': sb.Append("\\n"); break; case '\r': sb.Append("\\r"); break; case '\t': sb.Append("\\t"); break; case '\b': sb.Append("\\b"); break; case '\f': sb.Append("\\f"); break; default: if (c < ' ' || (forceASCII && c > 127)) { ushort val = c; sb.Append("\\u").Append(val.ToString("X4")); } else sb.Append(c); break; } } string result = sb.ToString(); sb.Length = 0; return result; } private static JSONNode ParseElement(string token, bool quoted) { if (quoted) return token; if (token.Length <= 5) { string tmp = token.ToLower(); if (tmp == "false" || tmp == "true") return tmp == "true"; if (tmp == "null") return JSONNull.CreateOrGet(); } double val; if (double.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out val)) return val; else return token; } public static JSONNode Parse(string aJSON) { Stack stack = new Stack(); JSONNode ctx = null; int i = 0; StringBuilder Token = new StringBuilder(); string TokenName = ""; bool QuoteMode = false; bool TokenIsQuoted = false; bool HasNewlineChar = false; while (i < aJSON.Length) { switch (aJSON[i]) { case '{': if (QuoteMode) { Token.Append(aJSON[i]); break; } stack.Push(new JSONObject()); if (ctx != null) { ctx.Add(TokenName, stack.Peek()); } TokenName = ""; Token.Length = 0; ctx = stack.Peek(); HasNewlineChar = false; break; case '[': if (QuoteMode) { Token.Append(aJSON[i]); break; } stack.Push(new JSONArray()); if (ctx != null) { ctx.Add(TokenName, stack.Peek()); } TokenName = ""; Token.Length = 0; ctx = stack.Peek(); HasNewlineChar = false; break; case '}': case ']': if (QuoteMode) { Token.Append(aJSON[i]); break; } if (stack.Count == 0) throw new Exception("JSON Parse: Too many closing brackets"); stack.Pop(); if (Token.Length > 0 || TokenIsQuoted) ctx.Add(TokenName, ParseElement(Token.ToString(), TokenIsQuoted)); if (ctx != null) ctx.Inline = !HasNewlineChar; TokenIsQuoted = false; TokenName = ""; Token.Length = 0; if (stack.Count > 0) ctx = stack.Peek(); break; case ':': if (QuoteMode) { Token.Append(aJSON[i]); break; } TokenName = Token.ToString(); Token.Length = 0; TokenIsQuoted = false; break; case '"': QuoteMode ^= true; TokenIsQuoted |= QuoteMode; break; case ',': if (QuoteMode) { Token.Append(aJSON[i]); break; } if (Token.Length > 0 || TokenIsQuoted) ctx.Add(TokenName, ParseElement(Token.ToString(), TokenIsQuoted)); TokenIsQuoted = false; TokenName = ""; Token.Length = 0; TokenIsQuoted = false; break; case '\r': case '\n': HasNewlineChar = true; break; case ' ': case '\t': if (QuoteMode) Token.Append(aJSON[i]); break; case '\\': ++i; if (QuoteMode) { char C = aJSON[i]; switch (C) { case 't': Token.Append('\t'); break; case 'r': Token.Append('\r'); break; case 'n': Token.Append('\n'); break; case 'b': Token.Append('\b'); break; case 'f': Token.Append('\f'); break; case 'u': { string s = aJSON.Substring(i + 1, 4); Token.Append((char)int.Parse( s, System.Globalization.NumberStyles.AllowHexSpecifier)); i += 4; break; } default: Token.Append(C); break; } } break; case '/': if (allowLineComments && !QuoteMode && i + 1 < aJSON.Length && aJSON[i + 1] == '/') { while (++i < aJSON.Length && aJSON[i] != '\n' && aJSON[i] != '\r') ; break; } Token.Append(aJSON[i]); break; case '\uFEFF': // remove / ignore BOM (Byte Order Mark) break; default: Token.Append(aJSON[i]); break; } ++i; } if (QuoteMode) { throw new Exception("JSON Parse: Quotation marks seems to be messed up."); } if (ctx == null) return ParseElement(Token.ToString(), TokenIsQuoted); return ctx; } } // End of JSONNode public partial class JSONArray : JSONNode { private List m_List = new List(); private bool inline = false; public override bool Inline { get { return inline; } set { inline = value; } } public override JSONNodeType Tag { get { return JSONNodeType.Array; } } public override bool IsArray { get { return true; } } public override Enumerator GetEnumerator() { return new Enumerator(m_List.GetEnumerator()); } public override JSONNode this[int aIndex] { get { if (aIndex < 0 || aIndex >= m_List.Count) return new JSONLazyCreator(this); return m_List[aIndex]; } set { if (value == null) value = JSONNull.CreateOrGet(); if (aIndex < 0 || aIndex >= m_List.Count) m_List.Add(value); else m_List[aIndex] = value; } } public override JSONNode this[string aKey] { get { return new JSONLazyCreator(this); } set { if (value == null) value = JSONNull.CreateOrGet(); m_List.Add(value); } } public override int Count { get { return m_List.Count; } } public override void Add(string aKey, JSONNode aItem) { if (aItem == null) aItem = JSONNull.CreateOrGet(); m_List.Add(aItem); } public override JSONNode Remove(int aIndex) { if (aIndex < 0 || aIndex >= m_List.Count) return null; JSONNode tmp = m_List[aIndex]; m_List.RemoveAt(aIndex); return tmp; } public override JSONNode Remove(JSONNode aNode) { m_List.Remove(aNode); return aNode; } public override void Clear() { m_List.Clear(); } public override JSONNode Clone() { var node = new JSONArray(); node.m_List.Capacity = m_List.Capacity; foreach (var n in m_List) { if (n != null) node.Add(n.Clone()); else node.Add(null); } return node; } public override IEnumerable Children { get { foreach (JSONNode N in m_List) yield return N; } } internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode) { aSB.Append('['); int count = m_List.Count; if (inline) aMode = JSONTextMode.Compact; for (int i = 0; i < count; i++) { if (i > 0) aSB.Append(','); if (aMode == JSONTextMode.Indent) aSB.AppendLine(); if (aMode == JSONTextMode.Indent) aSB.Append(' ', aIndent + aIndentInc); m_List[i].WriteToStringBuilder(aSB, aIndent + aIndentInc, aIndentInc, aMode); } if (aMode == JSONTextMode.Indent) aSB.AppendLine().Append(' ', aIndent); aSB.Append(']'); } } // End of JSONArray public partial class JSONObject : JSONNode { private Dictionary m_Dict = new Dictionary(); private bool inline = false; public override bool Inline { get { return inline; } set { inline = value; } } public override JSONNodeType Tag { get { return JSONNodeType.Object; } } public override bool IsObject { get { return true; } } public override Enumerator GetEnumerator() { return new Enumerator(m_Dict.GetEnumerator()); } public override JSONNode this[string aKey] { get { if (m_Dict.ContainsKey(aKey)) return m_Dict[aKey]; else return new JSONLazyCreator(this, aKey); } set { if (value == null) value = JSONNull.CreateOrGet(); if (m_Dict.ContainsKey(aKey)) m_Dict[aKey] = value; else m_Dict.Add(aKey, value); } } public override JSONNode this[int aIndex] { get { if (aIndex < 0 || aIndex >= m_Dict.Count) return null; return m_Dict.ElementAt(aIndex).Value; } set { if (value == null) value = JSONNull.CreateOrGet(); if (aIndex < 0 || aIndex >= m_Dict.Count) return; string key = m_Dict.ElementAt(aIndex).Key; m_Dict[key] = value; } } public override int Count { get { return m_Dict.Count; } } public override void Add(string aKey, JSONNode aItem) { if (aItem == null) aItem = JSONNull.CreateOrGet(); if (aKey != null) { if (m_Dict.ContainsKey(aKey)) m_Dict[aKey] = aItem; else m_Dict.Add(aKey, aItem); } else m_Dict.Add(Guid.NewGuid().ToString(), aItem); } public override JSONNode Remove(string aKey) { if (!m_Dict.ContainsKey(aKey)) return null; JSONNode tmp = m_Dict[aKey]; m_Dict.Remove(aKey); return tmp; } public override JSONNode Remove(int aIndex) { if (aIndex < 0 || aIndex >= m_Dict.Count) return null; var item = m_Dict.ElementAt(aIndex); m_Dict.Remove(item.Key); return item.Value; } public override JSONNode Remove(JSONNode aNode) { try { var item = m_Dict.Where(k => k.Value == aNode).First(); m_Dict.Remove(item.Key); return aNode; } catch { return null; } } public override void Clear() { m_Dict.Clear(); } public override JSONNode Clone() { var node = new JSONObject(); foreach (var n in m_Dict) { node.Add(n.Key, n.Value.Clone()); } return node; } public override bool HasKey(string aKey) { return m_Dict.ContainsKey(aKey); } public override JSONNode GetValueOrDefault(string aKey, JSONNode aDefault) { JSONNode res; if (m_Dict.TryGetValue(aKey, out res)) return res; return aDefault; } public override IEnumerable Children { get { foreach (KeyValuePair N in m_Dict) yield return N.Value; } } internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode) { aSB.Append('{'); bool first = true; if (inline) aMode = JSONTextMode.Compact; foreach (var k in m_Dict) { if (!first) aSB.Append(','); first = false; if (aMode == JSONTextMode.Indent) aSB.AppendLine(); if (aMode == JSONTextMode.Indent) aSB.Append(' ', aIndent + aIndentInc); aSB.Append('\"').Append(Escape(k.Key)).Append('\"'); if (aMode == JSONTextMode.Compact) aSB.Append(':'); else aSB.Append(" : "); k.Value.WriteToStringBuilder(aSB, aIndent + aIndentInc, aIndentInc, aMode); } if (aMode == JSONTextMode.Indent) aSB.AppendLine().Append(' ', aIndent); aSB.Append('}'); } } // End of JSONObject public partial class JSONString : JSONNode { private string m_Data; public override JSONNodeType Tag { get { return JSONNodeType.String; } } public override bool IsString { get { return true; } } public override Enumerator GetEnumerator() { return new Enumerator(); } public override string Value { get { return m_Data; } set { m_Data = value; } } public JSONString(string aData) { m_Data = aData; } public override JSONNode Clone() { return new JSONString(m_Data); } internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode) { aSB.Append('\"').Append(Escape(m_Data)).Append('\"'); } public override bool Equals(object obj) { if (base.Equals(obj)) return true; string s = obj as string; if (s != null) return m_Data == s; JSONString s2 = obj as JSONString; if (s2 != null) return m_Data == s2.m_Data; return false; } public override int GetHashCode() { return m_Data.GetHashCode(); } public override void Clear() { m_Data = ""; } } // End of JSONString public partial class JSONNumber : JSONNode { private double m_Data; public override JSONNodeType Tag { get { return JSONNodeType.Number; } } public override bool IsNumber { get { return true; } } public override Enumerator GetEnumerator() { return new Enumerator(); } public override string Value { get { return m_Data.ToString(CultureInfo.InvariantCulture); } set { double v; if (double.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out v)) m_Data = v; } } public override double AsDouble { get { return m_Data; } set { m_Data = value; } } public override long AsLong { get { return (long)m_Data; } set { m_Data = value; } } public override ulong AsULong { get { return (ulong)m_Data; } set { m_Data = value; } } public JSONNumber(double aData) { m_Data = aData; } public JSONNumber(string aData) { Value = aData; } public override JSONNode Clone() { return new JSONNumber(m_Data); } internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode) { aSB.Append(Value.ToString(CultureInfo.InvariantCulture)); } private static bool IsNumeric(object value) { return value is int || value is uint || value is float || value is double || value is decimal || value is long || value is ulong || value is short || value is ushort || value is sbyte || value is byte; } public override bool Equals(object obj) { if (obj == null) return false; if (base.Equals(obj)) return true; JSONNumber s2 = obj as JSONNumber; if (s2 != null) return m_Data == s2.m_Data; if (IsNumeric(obj)) return Convert.ToDouble(obj) == m_Data; return false; } public override int GetHashCode() { return m_Data.GetHashCode(); } public override void Clear() { m_Data = 0; } } // End of JSONNumber public partial class JSONBool : JSONNode { private bool m_Data; public override JSONNodeType Tag { get { return JSONNodeType.Boolean; } } public override bool IsBoolean { get { return true; } } public override Enumerator GetEnumerator() { return new Enumerator(); } public override string Value { get { return m_Data.ToString(); } set { bool v; if (bool.TryParse(value, out v)) m_Data = v; } } public override bool AsBool { get { return m_Data; } set { m_Data = value; } } public JSONBool(bool aData) { m_Data = aData; } public JSONBool(string aData) { Value = aData; } public override JSONNode Clone() { return new JSONBool(m_Data); } internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode) { aSB.Append((m_Data) ? "true" : "false"); } public override bool Equals(object obj) { if (obj == null) return false; if (obj is bool) return m_Data == (bool)obj; return false; } public override int GetHashCode() { return m_Data.GetHashCode(); } public override void Clear() { m_Data = false; } } // End of JSONBool public partial class JSONNull : JSONNode { static JSONNull m_StaticInstance = new JSONNull(); public static bool reuseSameInstance = true; public static JSONNull CreateOrGet() { if (reuseSameInstance) return m_StaticInstance; return new JSONNull(); } private JSONNull() { } public override JSONNodeType Tag { get { return JSONNodeType.NullValue; } } public override bool IsNull { get { return true; } } public override Enumerator GetEnumerator() { return new Enumerator(); } public override string Value { get { return "null"; } set { } } public override bool AsBool { get { return false; } set { } } public override JSONNode Clone() { return CreateOrGet(); } public override bool Equals(object obj) { if (object.ReferenceEquals(this, obj)) return true; return (obj is JSONNull); } public override int GetHashCode() { return 0; } internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode) { aSB.Append("null"); } } // End of JSONNull internal partial class JSONLazyCreator : JSONNode { private JSONNode m_Node = null; private string m_Key = null; public override JSONNodeType Tag { get { return JSONNodeType.None; } } public override Enumerator GetEnumerator() { return new Enumerator(); } public JSONLazyCreator(JSONNode aNode) { m_Node = aNode; m_Key = null; } public JSONLazyCreator(JSONNode aNode, string aKey) { m_Node = aNode; m_Key = aKey; } private T Set(T aVal) where T : JSONNode { if (m_Key == null) m_Node.Add(aVal); else m_Node.Add(m_Key, aVal); m_Node = null; // Be GC friendly. return aVal; } public override JSONNode this[int aIndex] { get { return new JSONLazyCreator(this); } set { Set(new JSONArray()).Add(value); } } public override JSONNode this[string aKey] { get { return new JSONLazyCreator(this, aKey); } set { Set(new JSONObject()).Add(aKey, value); } } public override void Add(JSONNode aItem) { Set(new JSONArray()).Add(aItem); } public override void Add(string aKey, JSONNode aItem) { Set(new JSONObject()).Add(aKey, aItem); } public static bool operator ==(JSONLazyCreator a, object b) { if (b == null) return true; return System.Object.ReferenceEquals(a, b); } public static bool operator !=(JSONLazyCreator a, object b) { return !(a == b); } public override bool Equals(object obj) { if (obj == null) return true; return System.Object.ReferenceEquals(this, obj); } public override int GetHashCode() { return 0; } public override int AsInt { get { Set(new JSONNumber(0)); return 0; } set { Set(new JSONNumber(value)); } } public override float AsFloat { get { Set(new JSONNumber(0.0f)); return 0.0f; } set { Set(new JSONNumber(value)); } } public override double AsDouble { get { Set(new JSONNumber(0.0)); return 0.0; } set { Set(new JSONNumber(value)); } } public override long AsLong { get { if (longAsString) Set(new JSONString("0")); else Set(new JSONNumber(0.0)); return 0L; } set { if (longAsString) Set(new JSONString(value.ToString(CultureInfo.InvariantCulture))); else Set(new JSONNumber(value)); } } public override ulong AsULong { get { if (longAsString) Set(new JSONString("0")); else Set(new JSONNumber(0.0)); return 0L; } set { if (longAsString) Set(new JSONString(value.ToString(CultureInfo.InvariantCulture))); else Set(new JSONNumber(value)); } } public override bool AsBool { get { Set(new JSONBool(false)); return false; } set { Set(new JSONBool(value)); } } public override JSONArray AsArray { get { return Set(new JSONArray()); } } public override JSONObject AsObject { get { return Set(new JSONObject()); } } internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode) { aSB.Append("null"); } } // End of JSONLazyCreator public static class JSON { public static JSONNode Parse(string aJSON) { return JSONNode.Parse(aJSON); } } } ================================================ FILE: VirtueSky/SimpleJSON/SimpleJSON.cs.meta ================================================ fileFormatVersion: 2 guid: e5263f587bfd4e440aba9b1b9996004c MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/SimpleJSON/SimpleJSONBinary.cs ================================================ //#define USE_SharpZipLib /* * * * * * This is an extension of the SimpleJSON framework to provide methods to * serialize a JSON object tree into a compact binary format. Optionally the * binary stream can be compressed with the SharpZipLib when using the define * "USE_SharpZipLib" * * Those methods where originally part of the framework but since it's rarely * used I've extracted this part into this seperate module file. * * You can use the define "SimpleJSON_ExcludeBinary" to selectively disable * this extension without the need to remove the file from the project. * * If you want to use compression when saving to file / stream / B64 you have to include * SharpZipLib ( http://www.icsharpcode.net/opensource/sharpziplib/ ) in your project and * define "USE_SharpZipLib" at the top of the file * * * The MIT License (MIT) * * Copyright (c) 2012-2017 Markus Göbel (Bunny83) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * * */ using System; namespace VirtueSky.SimpleJSON { #if !SimpleJSON_ExcludeBinary public abstract partial class JSONNode { public abstract void SerializeBinary(System.IO.BinaryWriter aWriter); public void SaveToBinaryStream(System.IO.Stream aData) { var W = new System.IO.BinaryWriter(aData); SerializeBinary(W); } #if USE_SharpZipLib public void SaveToCompressedStream(System.IO.Stream aData) { using (var gzipOut = new ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream(aData)) { gzipOut.IsStreamOwner = false; SaveToBinaryStream(gzipOut); gzipOut.Close(); } } public void SaveToCompressedFile(string aFileName) { System.IO.Directory.CreateDirectory((new System.IO.FileInfo(aFileName)).Directory.FullName); using(var F = System.IO.File.OpenWrite(aFileName)) { SaveToCompressedStream(F); } } public string SaveToCompressedBase64() { using (var stream = new System.IO.MemoryStream()) { SaveToCompressedStream(stream); stream.Position = 0; return System.Convert.ToBase64String(stream.ToArray()); } } #else public void SaveToCompressedStream(System.IO.Stream aData) { throw new Exception( "Can't use compressed functions. You need include the SharpZipLib and uncomment the define at the top of SimpleJSON"); } public void SaveToCompressedFile(string aFileName) { throw new Exception( "Can't use compressed functions. You need include the SharpZipLib and uncomment the define at the top of SimpleJSON"); } public string SaveToCompressedBase64() { throw new Exception( "Can't use compressed functions. You need include the SharpZipLib and uncomment the define at the top of SimpleJSON"); } #endif public void SaveToBinaryFile(string aFileName) { System.IO.Directory.CreateDirectory((new System.IO.FileInfo(aFileName)).Directory .FullName); using (var F = System.IO.File.OpenWrite(aFileName)) { SaveToBinaryStream(F); } } public string SaveToBinaryBase64() { using (var stream = new System.IO.MemoryStream()) { SaveToBinaryStream(stream); stream.Position = 0; return System.Convert.ToBase64String(stream.ToArray()); } } public static JSONNode DeserializeBinary(System.IO.BinaryReader aReader) { JSONNodeType type = (JSONNodeType)aReader.ReadByte(); switch (type) { case JSONNodeType.Array: { int count = aReader.ReadInt32(); JSONArray tmp = new JSONArray(); for (int i = 0; i < count; i++) tmp.Add(DeserializeBinary(aReader)); return tmp; } case JSONNodeType.Object: { int count = aReader.ReadInt32(); JSONObject tmp = new JSONObject(); for (int i = 0; i < count; i++) { string key = aReader.ReadString(); var val = DeserializeBinary(aReader); tmp.Add(key, val); } return tmp; } case JSONNodeType.String: { return new JSONString(aReader.ReadString()); } case JSONNodeType.Number: { return new JSONNumber(aReader.ReadDouble()); } case JSONNodeType.Boolean: { return new JSONBool(aReader.ReadBoolean()); } case JSONNodeType.NullValue: { return JSONNull.CreateOrGet(); } default: { throw new Exception("Error deserializing JSON. Unknown tag: " + type); } } } #if USE_SharpZipLib public static JSONNode LoadFromCompressedStream(System.IO.Stream aData) { var zin = new ICSharpCode.SharpZipLib.BZip2.BZip2InputStream(aData); return LoadFromBinaryStream(zin); } public static JSONNode LoadFromCompressedFile(string aFileName) { using(var F = System.IO.File.OpenRead(aFileName)) { return LoadFromCompressedStream(F); } } public static JSONNode LoadFromCompressedBase64(string aBase64) { var tmp = System.Convert.FromBase64String(aBase64); var stream = new System.IO.MemoryStream(tmp); stream.Position = 0; return LoadFromCompressedStream(stream); } #else public static JSONNode LoadFromCompressedFile(string aFileName) { throw new Exception( "Can't use compressed functions. You need include the SharpZipLib and uncomment the define at the top of SimpleJSON"); } public static JSONNode LoadFromCompressedStream(System.IO.Stream aData) { throw new Exception( "Can't use compressed functions. You need include the SharpZipLib and uncomment the define at the top of SimpleJSON"); } public static JSONNode LoadFromCompressedBase64(string aBase64) { throw new Exception( "Can't use compressed functions. You need include the SharpZipLib and uncomment the define at the top of SimpleJSON"); } #endif public static JSONNode LoadFromBinaryStream(System.IO.Stream aData) { using (var R = new System.IO.BinaryReader(aData)) { return DeserializeBinary(R); } } public static JSONNode LoadFromBinaryFile(string aFileName) { using (var F = System.IO.File.OpenRead(aFileName)) { return LoadFromBinaryStream(F); } } public static JSONNode LoadFromBinaryBase64(string aBase64) { var tmp = System.Convert.FromBase64String(aBase64); var stream = new System.IO.MemoryStream(tmp); stream.Position = 0; return LoadFromBinaryStream(stream); } } public partial class JSONArray : JSONNode { public override void SerializeBinary(System.IO.BinaryWriter aWriter) { aWriter.Write((byte)JSONNodeType.Array); aWriter.Write(m_List.Count); for (int i = 0; i < m_List.Count; i++) { m_List[i].SerializeBinary(aWriter); } } } public partial class JSONObject : JSONNode { public override void SerializeBinary(System.IO.BinaryWriter aWriter) { aWriter.Write((byte)JSONNodeType.Object); aWriter.Write(m_Dict.Count); foreach (string K in m_Dict.Keys) { aWriter.Write(K); m_Dict[K].SerializeBinary(aWriter); } } } public partial class JSONString : JSONNode { public override void SerializeBinary(System.IO.BinaryWriter aWriter) { aWriter.Write((byte)JSONNodeType.String); aWriter.Write(m_Data); } } public partial class JSONNumber : JSONNode { public override void SerializeBinary(System.IO.BinaryWriter aWriter) { aWriter.Write((byte)JSONNodeType.Number); aWriter.Write(m_Data); } } public partial class JSONBool : JSONNode { public override void SerializeBinary(System.IO.BinaryWriter aWriter) { aWriter.Write((byte)JSONNodeType.Boolean); aWriter.Write(m_Data); } } public partial class JSONNull : JSONNode { public override void SerializeBinary(System.IO.BinaryWriter aWriter) { aWriter.Write((byte)JSONNodeType.NullValue); } } internal partial class JSONLazyCreator : JSONNode { public override void SerializeBinary(System.IO.BinaryWriter aWriter) { } } #endif } ================================================ FILE: VirtueSky/SimpleJSON/SimpleJSONBinary.cs.meta ================================================ fileFormatVersion: 2 guid: 49ead892e1332124380a7d5e810b51af MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/SimpleJSON/SimpleJSONDotNetTypes.cs ================================================ #region License and information /* * * * * * * Extension file for the SimpleJSON framework for better support of some common * .NET types. It does only work together with the SimpleJSON.cs * It provides direct conversion support for types like decimal, char, byte, * sbyte, short, ushort, uint, DateTime, TimeSpan and Guid. In addition there * are conversion helpers for converting an array of number values into a byte[] * or a List as well as converting an array of string values into a string[] * or List. * Finally there are some additional type conversion operators for some nullable * types like short?, int?, float?, double?, long? and bool?. They will actually * assign a JSONNull value when it's null or a JSONNumber when it's not. * * The MIT License (MIT) * * Copyright (c) 2020 Markus Göbel (Bunny83) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * * */ #endregion License and information namespace VirtueSky.SimpleJSON { using System.Globalization; using System.Collections.Generic; public partial class JSONNode { #region Decimal public virtual decimal AsDecimal { get { decimal result; if (!decimal.TryParse(Value, out result)) result = 0; return result; } set { Value = value.ToString(); } } public static implicit operator JSONNode(decimal aDecimal) { return new JSONString(aDecimal.ToString()); } public static implicit operator decimal(JSONNode aNode) { return aNode.AsDecimal; } #endregion Decimal #region Char public virtual char AsChar { get { if (IsString && Value.Length > 0) return Value[0]; if (IsNumber) return (char)AsInt; return '\0'; } set { if (IsString) Value = value.ToString(); else if (IsNumber) AsInt = (int)value; } } public static implicit operator JSONNode(char aChar) { return new JSONString(aChar.ToString()); } public static implicit operator char(JSONNode aNode) { return aNode.AsChar; } #endregion Decimal #region UInt public virtual uint AsUInt { get { return (uint)AsDouble; } set { AsDouble = value; } } public static implicit operator JSONNode(uint aUInt) { return new JSONNumber(aUInt); } public static implicit operator uint(JSONNode aNode) { return aNode.AsUInt; } #endregion UInt #region Byte public virtual byte AsByte { get { return (byte)AsInt; } set { AsInt = value; } } public static implicit operator JSONNode(byte aByte) { return new JSONNumber(aByte); } public static implicit operator byte(JSONNode aNode) { return aNode.AsByte; } #endregion Byte #region SByte public virtual sbyte AsSByte { get { return (sbyte)AsInt; } set { AsInt = value; } } public static implicit operator JSONNode(sbyte aSByte) { return new JSONNumber(aSByte); } public static implicit operator sbyte(JSONNode aNode) { return aNode.AsSByte; } #endregion SByte #region Short public virtual short AsShort { get { return (short)AsInt; } set { AsInt = value; } } public static implicit operator JSONNode(short aShort) { return new JSONNumber(aShort); } public static implicit operator short(JSONNode aNode) { return aNode.AsShort; } #endregion Short #region UShort public virtual ushort AsUShort { get { return (ushort)AsInt; } set { AsInt = value; } } public static implicit operator JSONNode(ushort aUShort) { return new JSONNumber(aUShort); } public static implicit operator ushort(JSONNode aNode) { return aNode.AsUShort; } #endregion UShort #region DateTime public virtual System.DateTime AsDateTime { get { System.DateTime result; if (!System.DateTime.TryParse(Value, CultureInfo.InvariantCulture, DateTimeStyles.None, out result)) result = new System.DateTime(0); return result; } set { Value = value.ToString(CultureInfo.InvariantCulture); } } public static implicit operator JSONNode(System.DateTime aDateTime) { return new JSONString(aDateTime.ToString(CultureInfo.InvariantCulture)); } public static implicit operator System.DateTime(JSONNode aNode) { return aNode.AsDateTime; } #endregion DateTime #region TimeSpan public virtual System.TimeSpan AsTimeSpan { get { System.TimeSpan result; if (!System.TimeSpan.TryParse(Value, CultureInfo.InvariantCulture, out result)) result = new System.TimeSpan(0); return result; } set { Value = value.ToString(); } } public static implicit operator JSONNode(System.TimeSpan aTimeSpan) { return new JSONString(aTimeSpan.ToString()); } public static implicit operator System.TimeSpan(JSONNode aNode) { return aNode.AsTimeSpan; } #endregion TimeSpan #region Guid public virtual System.Guid AsGuid { get { System.Guid result; System.Guid.TryParse(Value, out result); return result; } set { Value = value.ToString(); } } public static implicit operator JSONNode(System.Guid aGuid) { return new JSONString(aGuid.ToString()); } public static implicit operator System.Guid(JSONNode aNode) { return aNode.AsGuid; } #endregion Guid #region ByteArray public virtual byte[] AsByteArray { get { if (this.IsNull || !this.IsArray) return null; int count = Count; byte[] result = new byte[count]; for (int i = 0; i < count; i++) result[i] = this[i].AsByte; return result; } set { if (!IsArray || value == null) return; Clear(); for (int i = 0; i < value.Length; i++) Add(value[i]); } } public static implicit operator JSONNode(byte[] aByteArray) { return new JSONArray { AsByteArray = aByteArray }; } public static implicit operator byte[](JSONNode aNode) { return aNode.AsByteArray; } #endregion ByteArray #region ByteList public virtual List AsByteList { get { if (this.IsNull || !this.IsArray) return null; int count = Count; List result = new List(count); for (int i = 0; i < count; i++) result.Add(this[i].AsByte); return result; } set { if (!IsArray || value == null) return; Clear(); for (int i = 0; i < value.Count; i++) Add(value[i]); } } public static implicit operator JSONNode(List aByteList) { return new JSONArray { AsByteList = aByteList }; } public static implicit operator List(JSONNode aNode) { return aNode.AsByteList; } #endregion ByteList #region StringArray public virtual string[] AsStringArray { get { if (this.IsNull || !this.IsArray) return null; int count = Count; string[] result = new string[count]; for (int i = 0; i < count; i++) result[i] = this[i].Value; return result; } set { if (!IsArray || value == null) return; Clear(); for (int i = 0; i < value.Length; i++) Add(value[i]); } } public static implicit operator JSONNode(string[] aStringArray) { return new JSONArray { AsStringArray = aStringArray }; } public static implicit operator string[](JSONNode aNode) { return aNode.AsStringArray; } #endregion StringArray #region StringList public virtual List AsStringList { get { if (this.IsNull || !this.IsArray) return null; int count = Count; List result = new List(count); for (int i = 0; i < count; i++) result.Add(this[i].Value); return result; } set { if (!IsArray || value == null) return; Clear(); for (int i = 0; i < value.Count; i++) Add(value[i]); } } public static implicit operator JSONNode(List aStringList) { return new JSONArray { AsStringList = aStringList }; } public static implicit operator List(JSONNode aNode) { return aNode.AsStringList; } #endregion StringList #region NullableTypes public static implicit operator JSONNode(int? aValue) { if (aValue == null) return JSONNull.CreateOrGet(); return new JSONNumber((int)aValue); } public static implicit operator int?(JSONNode aNode) { if (aNode == null || aNode.IsNull) return null; return aNode.AsInt; } public static implicit operator JSONNode(float? aValue) { if (aValue == null) return JSONNull.CreateOrGet(); return new JSONNumber((float)aValue); } public static implicit operator float?(JSONNode aNode) { if (aNode == null || aNode.IsNull) return null; return aNode.AsFloat; } public static implicit operator JSONNode(double? aValue) { if (aValue == null) return JSONNull.CreateOrGet(); return new JSONNumber((double)aValue); } public static implicit operator double?(JSONNode aNode) { if (aNode == null || aNode.IsNull) return null; return aNode.AsDouble; } public static implicit operator JSONNode(bool? aValue) { if (aValue == null) return JSONNull.CreateOrGet(); return new JSONBool((bool)aValue); } public static implicit operator bool?(JSONNode aNode) { if (aNode == null || aNode.IsNull) return null; return aNode.AsBool; } public static implicit operator JSONNode(long? aValue) { if (aValue == null) return JSONNull.CreateOrGet(); return new JSONNumber((long)aValue); } public static implicit operator long?(JSONNode aNode) { if (aNode == null || aNode.IsNull) return null; return aNode.AsLong; } public static implicit operator JSONNode(short? aValue) { if (aValue == null) return JSONNull.CreateOrGet(); return new JSONNumber((short)aValue); } public static implicit operator short?(JSONNode aNode) { if (aNode == null || aNode.IsNull) return null; return aNode.AsShort; } #endregion NullableTypes } } ================================================ FILE: VirtueSky/SimpleJSON/SimpleJSONDotNetTypes.cs.meta ================================================ fileFormatVersion: 2 guid: e1f66c32e2f2f89448cff7c8a69c768d MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/SimpleJSON/SimpleJSONUnity.cs ================================================ #if UNITY_5_3_OR_NEWER #region License and information /* * * * * * * Unity extension for the SimpleJSON framework. It does only work together with * the SimpleJSON.cs * It provides several helpers and conversion operators to serialize/deserialize * common Unity types such as Vector2/3/4, Rect, RectOffset, Quaternion and * Matrix4x4 as JSONObject or JSONArray. * This extension will add 3 static settings to the JSONNode class: * ( VectorContainerType, QuaternionContainerType, RectContainerType ) which * control what node type should be used for serializing the given type. So a * Vector3 as array would look like [12,32,24] and {"x":12, "y":32, "z":24} as * object. * * * The MIT License (MIT) * * Copyright (c) 2012-2017 Markus Göbel (Bunny83) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * * */ #endregion License and information using UnityEngine; namespace VirtueSky.SimpleJSON { public enum JSONContainerType { Array, Object } public partial class JSONNode { public static byte Color32DefaultAlpha = 255; public static float ColorDefaultAlpha = 1f; public static JSONContainerType VectorContainerType = JSONContainerType.Array; public static JSONContainerType QuaternionContainerType = JSONContainerType.Array; public static JSONContainerType RectContainerType = JSONContainerType.Array; public static JSONContainerType ColorContainerType = JSONContainerType.Array; private static JSONNode GetContainer(JSONContainerType aType) { if (aType == JSONContainerType.Array) return new JSONArray(); return new JSONObject(); } #region implicit conversion operators public static implicit operator JSONNode(Vector2 aVec) { JSONNode n = GetContainer(VectorContainerType); n.WriteVector2(aVec); return n; } public static implicit operator JSONNode(Vector3 aVec) { JSONNode n = GetContainer(VectorContainerType); n.WriteVector3(aVec); return n; } public static implicit operator JSONNode(Vector4 aVec) { JSONNode n = GetContainer(VectorContainerType); n.WriteVector4(aVec); return n; } public static implicit operator JSONNode(Color aCol) { JSONNode n = GetContainer(ColorContainerType); n.WriteColor(aCol); return n; } public static implicit operator JSONNode(Color32 aCol) { JSONNode n = GetContainer(ColorContainerType); n.WriteColor32(aCol); return n; } public static implicit operator JSONNode(Quaternion aRot) { JSONNode n = GetContainer(QuaternionContainerType); n.WriteQuaternion(aRot); return n; } public static implicit operator JSONNode(Rect aRect) { JSONNode n = GetContainer(RectContainerType); n.WriteRect(aRect); return n; } public static implicit operator JSONNode(RectOffset aRect) { JSONNode n = GetContainer(RectContainerType); n.WriteRectOffset(aRect); return n; } public static implicit operator Vector2(JSONNode aNode) { return aNode.ReadVector2(); } public static implicit operator Vector3(JSONNode aNode) { return aNode.ReadVector3(); } public static implicit operator Vector4(JSONNode aNode) { return aNode.ReadVector4(); } public static implicit operator Color(JSONNode aNode) { return aNode.ReadColor(); } public static implicit operator Color32(JSONNode aNode) { return aNode.ReadColor32(); } public static implicit operator Quaternion(JSONNode aNode) { return aNode.ReadQuaternion(); } public static implicit operator Rect(JSONNode aNode) { return aNode.ReadRect(); } public static implicit operator RectOffset(JSONNode aNode) { return aNode.ReadRectOffset(); } #endregion implicit conversion operators #region Vector2 public Vector2 ReadVector2(Vector2 aDefault) { if (IsObject) return new Vector2(this["x"].AsFloat, this["y"].AsFloat); if (IsArray) return new Vector2(this[0].AsFloat, this[1].AsFloat); return aDefault; } public Vector2 ReadVector2(string aXName, string aYName) { if (IsObject) { return new Vector2(this[aXName].AsFloat, this[aYName].AsFloat); } return Vector2.zero; } public Vector2 ReadVector2() { return ReadVector2(Vector2.zero); } public JSONNode WriteVector2(Vector2 aVec, string aXName = "x", string aYName = "y") { if (IsObject) { Inline = true; this[aXName].AsFloat = aVec.x; this[aYName].AsFloat = aVec.y; } else if (IsArray) { Inline = true; this[0].AsFloat = aVec.x; this[1].AsFloat = aVec.y; } return this; } #endregion Vector2 #region Vector3 public Vector3 ReadVector3(Vector3 aDefault) { if (IsObject) return new Vector3(this["x"].AsFloat, this["y"].AsFloat, this["z"].AsFloat); if (IsArray) return new Vector3(this[0].AsFloat, this[1].AsFloat, this[2].AsFloat); return aDefault; } public Vector3 ReadVector3(string aXName, string aYName, string aZName) { if (IsObject) return new Vector3(this[aXName].AsFloat, this[aYName].AsFloat, this[aZName].AsFloat); return Vector3.zero; } public Vector3 ReadVector3() { return ReadVector3(Vector3.zero); } public JSONNode WriteVector3(Vector3 aVec, string aXName = "x", string aYName = "y", string aZName = "z") { if (IsObject) { Inline = true; this[aXName].AsFloat = aVec.x; this[aYName].AsFloat = aVec.y; this[aZName].AsFloat = aVec.z; } else if (IsArray) { Inline = true; this[0].AsFloat = aVec.x; this[1].AsFloat = aVec.y; this[2].AsFloat = aVec.z; } return this; } #endregion Vector3 #region Vector4 public Vector4 ReadVector4(Vector4 aDefault) { if (IsObject) return new Vector4(this["x"].AsFloat, this["y"].AsFloat, this["z"].AsFloat, this["w"].AsFloat); if (IsArray) return new Vector4(this[0].AsFloat, this[1].AsFloat, this[2].AsFloat, this[3].AsFloat); return aDefault; } public Vector4 ReadVector4() { return ReadVector4(Vector4.zero); } public JSONNode WriteVector4(Vector4 aVec) { if (IsObject) { Inline = true; this["x"].AsFloat = aVec.x; this["y"].AsFloat = aVec.y; this["z"].AsFloat = aVec.z; this["w"].AsFloat = aVec.w; } else if (IsArray) { Inline = true; this[0].AsFloat = aVec.x; this[1].AsFloat = aVec.y; this[2].AsFloat = aVec.z; this[3].AsFloat = aVec.w; } return this; } #endregion Vector4 #region Color / Color32 public Color ReadColor(Color aDefault) { if (IsObject) return new Color(this["r"].AsFloat, this["g"].AsFloat, this["b"].AsFloat, HasKey("a") ? this["a"].AsFloat : ColorDefaultAlpha); if (IsArray) return new Color(this[0].AsFloat, this[1].AsFloat, this[2].AsFloat, (Count > 3) ? this[3].AsFloat : ColorDefaultAlpha); return aDefault; } public Color ReadColor() { return ReadColor(Color.clear); } public JSONNode WriteColor(Color aCol) { if (IsObject) { Inline = true; this["r"].AsFloat = aCol.r; this["g"].AsFloat = aCol.g; this["b"].AsFloat = aCol.b; this["a"].AsFloat = aCol.a; } else if (IsArray) { Inline = true; this[0].AsFloat = aCol.r; this[1].AsFloat = aCol.g; this[2].AsFloat = aCol.b; this[3].AsFloat = aCol.a; } return this; } public Color32 ReadColor32(Color32 aDefault) { if (IsObject) return new Color32((byte)this["r"].AsInt, (byte)this["g"].AsInt, (byte)this["b"].AsInt, (byte)(HasKey("a") ? this["a"].AsInt : Color32DefaultAlpha)); if (IsArray) return new Color32((byte)this[0].AsInt, (byte)this[1].AsInt, (byte)this[2].AsInt, (byte)((Count > 3) ? this[3].AsInt : Color32DefaultAlpha)); return aDefault; } public Color32 ReadColor32() { return ReadColor32(new Color32()); } public JSONNode WriteColor32(Color32 aCol) { if (IsObject) { Inline = true; this["r"].AsInt = aCol.r; this["g"].AsInt = aCol.g; this["b"].AsInt = aCol.b; this["a"].AsInt = aCol.a; } else if (IsArray) { Inline = true; this[0].AsInt = aCol.r; this[1].AsInt = aCol.g; this[2].AsInt = aCol.b; this[3].AsInt = aCol.a; } return this; } #endregion Color / Color32 #region Quaternion public Quaternion ReadQuaternion(Quaternion aDefault) { if (IsObject) return new Quaternion(this["x"].AsFloat, this["y"].AsFloat, this["z"].AsFloat, this["w"].AsFloat); if (IsArray) return new Quaternion(this[0].AsFloat, this[1].AsFloat, this[2].AsFloat, this[3].AsFloat); return aDefault; } public Quaternion ReadQuaternion() { return ReadQuaternion(Quaternion.identity); } public JSONNode WriteQuaternion(Quaternion aRot) { if (IsObject) { Inline = true; this["x"].AsFloat = aRot.x; this["y"].AsFloat = aRot.y; this["z"].AsFloat = aRot.z; this["w"].AsFloat = aRot.w; } else if (IsArray) { Inline = true; this[0].AsFloat = aRot.x; this[1].AsFloat = aRot.y; this[2].AsFloat = aRot.z; this[3].AsFloat = aRot.w; } return this; } #endregion Quaternion #region Rect public Rect ReadRect(Rect aDefault) { if (IsObject) return new Rect(this["x"].AsFloat, this["y"].AsFloat, this["width"].AsFloat, this["height"].AsFloat); if (IsArray) return new Rect(this[0].AsFloat, this[1].AsFloat, this[2].AsFloat, this[3].AsFloat); return aDefault; } public Rect ReadRect() { return ReadRect(new Rect()); } public JSONNode WriteRect(Rect aRect) { if (IsObject) { Inline = true; this["x"].AsFloat = aRect.x; this["y"].AsFloat = aRect.y; this["width"].AsFloat = aRect.width; this["height"].AsFloat = aRect.height; } else if (IsArray) { Inline = true; this[0].AsFloat = aRect.x; this[1].AsFloat = aRect.y; this[2].AsFloat = aRect.width; this[3].AsFloat = aRect.height; } return this; } #endregion Rect #region RectOffset public RectOffset ReadRectOffset(RectOffset aDefault) { if (this is JSONObject) return new RectOffset(this["left"].AsInt, this["right"].AsInt, this["top"].AsInt, this["bottom"].AsInt); if (this is JSONArray) return new RectOffset(this[0].AsInt, this[1].AsInt, this[2].AsInt, this[3].AsInt); return aDefault; } public RectOffset ReadRectOffset() { return ReadRectOffset(new RectOffset()); } public JSONNode WriteRectOffset(RectOffset aRect) { if (IsObject) { Inline = true; this["left"].AsInt = aRect.left; this["right"].AsInt = aRect.right; this["top"].AsInt = aRect.top; this["bottom"].AsInt = aRect.bottom; } else if (IsArray) { Inline = true; this[0].AsInt = aRect.left; this[1].AsInt = aRect.right; this[2].AsInt = aRect.top; this[3].AsInt = aRect.bottom; } return this; } #endregion RectOffset #region Matrix4x4 public Matrix4x4 ReadMatrix() { Matrix4x4 result = Matrix4x4.identity; if (IsArray) { for (int i = 0; i < 16; i++) { result[i] = this[i].AsFloat; } } return result; } public JSONNode WriteMatrix(Matrix4x4 aMatrix) { if (IsArray) { Inline = true; for (int i = 0; i < 16; i++) { this[i].AsFloat = aMatrix[i]; } } return this; } #endregion Matrix4x4 } } #endif ================================================ FILE: VirtueSky/SimpleJSON/SimpleJSONUnity.cs.meta ================================================ fileFormatVersion: 2 guid: e6d6a5e58d63bf34f9547da8fda47814 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/SimpleJSON/Virtuesky.Sunflower.SimpleJson.asmdef ================================================ { "name": "Virtuesky.Sunflower.SimpleJson" } ================================================ FILE: VirtueSky/SimpleJSON/Virtuesky.Sunflower.SimpleJson.asmdef.meta ================================================ fileFormatVersion: 2 guid: 98c7400721ddc874d9bad4ee2f3f66d6 AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/SimpleJSON.meta ================================================ fileFormatVersion: 2 guid: cb55fbcbb2ac561488658e5088c404b8 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/TouchInput/Editor/TouchInputManagerEditor.cs ================================================ using UnityEditor; using UnityEngine; using VirtueSky.UtilsEditor; namespace VirtueSky.TouchInput { [CustomEditor(typeof(TouchInputManager))] public class TouchInputManagerEditor : Editor { private SerializedProperty _inputEventTouchBegin; private SerializedProperty _inputEventTouchMove; private SerializedProperty _inputEventTouchStationary; private SerializedProperty _inputEventTouchEnd; private SerializedProperty _inputEventTouchCancel; private SerializedProperty _inputPreventTouchVariable; private SerializedProperty _preventTouch; private SerializedProperty _touchPosition; private const string path = "/InputEvent"; void Init() { _inputEventTouchBegin = serializedObject.FindProperty("inputEventTouchBegin"); _inputEventTouchMove = serializedObject.FindProperty("inputEventTouchMove"); _inputEventTouchStationary = serializedObject.FindProperty("inputEventTouchStationary"); _inputEventTouchEnd = serializedObject.FindProperty("inputEventTouchEnd"); _inputEventTouchCancel = serializedObject.FindProperty("inputEventTouchCancel"); _inputPreventTouchVariable = serializedObject.FindProperty("inputPreventTouchVariable"); _preventTouch = serializedObject.FindProperty("preventTouch"); _touchPosition = serializedObject.FindProperty("touchPosition"); } private void OnEnable() { Init(); } public override void OnInspectorGUI() { serializedObject.Update(); DrawEvent(ref _inputEventTouchBegin, "input_event_touch_begin"); DrawEvent(ref _inputEventTouchMove, "input_event_touch_move"); DrawEvent(ref _inputEventTouchStationary, "input_event_touch_stationary"); DrawEvent(ref _inputEventTouchEnd, "input_event_touch_end"); DrawEvent(ref _inputEventTouchCancel, "input_event_touch_cancel"); GUILayout.Space(5); DrawEvent(ref _inputPreventTouchVariable, "input_prevent_touch_variable"); GUILayout.Space(5); if (Application.isPlaying) { EditorGUILayout.PropertyField(_preventTouch); } GUILayout.Space(5); if (Application.isPlaying) { EditorGUILayout.PropertyField(_touchPosition); } EditorUtility.SetDirty(target); serializedObject.ApplyModifiedProperties(); //serializedObject.Update(); } void DrawEvent(ref SerializedProperty inputEvent, string eventName) where T : ScriptableObject { EditorGUILayout.BeginHorizontal(); EditorGUILayout.PropertyField(inputEvent); if (inputEvent.objectReferenceValue == null) { GUILayout.Space(2); if (GUILayout.Button("Create", GUILayout.Width(55))) { inputEvent.objectReferenceValue = CreateAsset.CreateAndGetScriptableAsset(path, eventName, false); } } EditorGUILayout.EndHorizontal(); } } } ================================================ FILE: VirtueSky/TouchInput/Editor/TouchInputManagerEditor.cs.meta ================================================ fileFormatVersion: 2 guid: 835c66fdab2646d09a76ee5dbefb37f3 timeCreated: 1720080548 ================================================ FILE: VirtueSky/TouchInput/Editor/Virtuesky.Sunflower.TouchInput.Editor.asmdef ================================================ { "name": "Virtuesky.Sunflower.TouchInput.Editor", "rootNamespace": "", "references": [ "GUID:fe2654b21280dcc4b8f7cff43f5cc40b", "GUID:c904f6d969e991d459a0843b71c22ec5", "GUID:bd40169efe8642149b1d2b72ba4903ce", "GUID:acb3cac55c622ec459c8caadf707623a", "GUID:35d694408290717499b3838802212c7f" ], "includePlatforms": [ "Editor" ], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], "versionDefines": [], "noEngineReferences": false } ================================================ FILE: VirtueSky/TouchInput/Editor/Virtuesky.Sunflower.TouchInput.Editor.asmdef.meta ================================================ fileFormatVersion: 2 guid: 7181056f59e7ba54bba1d2c0fd95040a AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/TouchInput/Editor.meta ================================================ fileFormatVersion: 2 guid: d8cf9d9d575f4974daa4cb8dee0308b1 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/TouchInput/Runtime/InputTouchEvent/InputEventTouchBegin.cs ================================================ using UnityEngine; using VirtueSky.Events; using VirtueSky.Inspector; namespace VirtueSky.TouchInput { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Touch Input/Event Touch Begin", fileName = "input_event_touch_begin")] [EditorIcon("scriptable_event")] public class InputEventTouchBegin : Vector3Event { } } ================================================ FILE: VirtueSky/TouchInput/Runtime/InputTouchEvent/InputEventTouchBegin.cs.meta ================================================ fileFormatVersion: 2 guid: ec1309b8f71347d18122f9aec5119ed8 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/TouchInput/Runtime/InputTouchEvent/InputEventTouchCancel.cs ================================================ using UnityEngine; using VirtueSky.Events; using VirtueSky.Inspector; namespace VirtueSky.TouchInput { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Touch Input/Event Touch Cancel", fileName = "input_event_touch_cancel")] [EditorIcon("scriptable_event")] public class InputEventTouchCancel : Vector3Event { } } ================================================ FILE: VirtueSky/TouchInput/Runtime/InputTouchEvent/InputEventTouchCancel.cs.meta ================================================ fileFormatVersion: 2 guid: d8fb1dea22af4b9a980d72ef7e9be012 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/TouchInput/Runtime/InputTouchEvent/InputEventTouchEnd.cs ================================================ using UnityEngine; using VirtueSky.Events; using VirtueSky.Inspector; namespace VirtueSky.TouchInput { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Touch Input/Event Touch End", fileName = "input_event_touch_end")] [EditorIcon("scriptable_event")] public class InputEventTouchEnd : Vector3Event { } } ================================================ FILE: VirtueSky/TouchInput/Runtime/InputTouchEvent/InputEventTouchEnd.cs.meta ================================================ fileFormatVersion: 2 guid: 81b183cd299f40398bab05815b4800a7 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/TouchInput/Runtime/InputTouchEvent/InputEventTouchMove.cs ================================================ using UnityEngine; using VirtueSky.Events; using VirtueSky.Inspector; namespace VirtueSky.TouchInput { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Touch Input/Event Touch Move", fileName = "input_event_touch_move")] [EditorIcon("scriptable_event")] public class InputEventTouchMove : Vector3Event { } } ================================================ FILE: VirtueSky/TouchInput/Runtime/InputTouchEvent/InputEventTouchMove.cs.meta ================================================ fileFormatVersion: 2 guid: 7df8998bdaa34b7da53c859d6b828ff5 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/TouchInput/Runtime/InputTouchEvent/InputEventTouchStationary.cs ================================================ using UnityEngine; using VirtueSky.Events; using VirtueSky.Inspector; namespace VirtueSky.TouchInput { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Touch Input/Event Touch Stationary", fileName = "input_event_touch_stationary")] [EditorIcon("scriptable_event")] public class InputEventTouchStationary : Vector3Event { } } ================================================ FILE: VirtueSky/TouchInput/Runtime/InputTouchEvent/InputEventTouchStationary.cs.meta ================================================ fileFormatVersion: 2 guid: 448e981eafa6406484aaae4ddb2250ea MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/TouchInput/Runtime/InputTouchEvent/InputPreventTouchVariable.cs ================================================ using UnityEngine; using VirtueSky.Inspector; using VirtueSky.Variables; namespace VirtueSky.TouchInput { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Touch Input/Variable Prevent Touch", fileName = "input_prevent_touch_variable")] [EditorIcon("scriptable_variable")] public class InputPreventTouchVariable : BooleanVariable { } } ================================================ FILE: VirtueSky/TouchInput/Runtime/InputTouchEvent/InputPreventTouchVariable.cs.meta ================================================ fileFormatVersion: 2 guid: 1c6aaa729cc54f81b082dd389895da05 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 8f06818ab5c1c06439abc547979c8edd, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/TouchInput/Runtime/InputTouchEvent.meta ================================================ fileFormatVersion: 2 guid: fe39cac498644a3995c160b428b65e74 timeCreated: 1720082877 ================================================ FILE: VirtueSky/TouchInput/Runtime/TouchInputManager.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.TouchInput { [EditorIcon("icon_controller")] public class TouchInputManager : MonoBehaviour { [SerializeField, Tooltip("Event A finger touched the screen")] private InputEventTouchBegin inputEventTouchBegin; [SerializeField, Tooltip("Event A finger moved on the screen")] private InputEventTouchMove inputEventTouchMove; [SerializeField, Tooltip("Event A finger is touching the screen but hasn't moved")] private InputEventTouchStationary inputEventTouchStationary; [SerializeField, Tooltip("Event A finger was lifted from the screen. This is the final phase of a touch")] private InputEventTouchEnd inputEventTouchEnd; [SerializeField, Tooltip("The system cancelled tracking for the touch")] private InputEventTouchCancel inputEventTouchCancel; [SerializeField, Tooltip("Prevent touch variable")] private InputPreventTouchVariable inputPreventTouchVariable; [SerializeField] private Vector3 touchPosition; [SerializeField] private bool preventTouch = false; private bool _mouseDown; private bool _mouseUpdate; private void OnEnable() { if (inputPreventTouchVariable != null) { inputPreventTouchVariable.Value = preventTouch; inputPreventTouchVariable.AddListener(OnChangePreventTouch); } } private void OnDisable() { if (inputPreventTouchVariable != null) { inputPreventTouchVariable.RemoveListener(OnChangePreventTouch); } } void OnChangePreventTouch(bool prevent) { preventTouch = prevent; } private void Update() { if (preventTouch) return; #if UNITY_EDITOR if (UnityEngine.Device.SystemInfo.deviceType != DeviceType.Desktop) { HandleTouch(); } else { HandleMouse(); } #else HandleTouch(); #endif } void HandleTouch() { if (Input.touchCount > 0) { Touch touch = Input.GetTouch(0); switch (touch.phase) { case TouchPhase.Began: if (inputEventTouchBegin != null) { inputEventTouchBegin.Raise(touch.position); } break; case TouchPhase.Moved: if (inputEventTouchMove != null) { inputEventTouchMove.Raise(touch.position); } break; case TouchPhase.Stationary: if (inputEventTouchStationary != null) { inputEventTouchStationary.Raise(touch.position); } break; case TouchPhase.Ended: if (inputEventTouchEnd != null) { inputEventTouchEnd.Raise(touch.position); } break; case TouchPhase.Canceled: if (inputEventTouchCancel != null) { inputEventTouchCancel.Raise(touch.position); } break; } touchPosition = touch.position; } } void HandleMouse() { if (Input.GetMouseButtonDown(0)) { if (!_mouseDown) { _mouseDown = true; _mouseUpdate = true; if (inputEventTouchBegin != null) { inputEventTouchBegin.Raise(Input.mousePosition); } touchPosition = Input.mousePosition; } } else if (Input.GetMouseButtonUp(0)) { _mouseDown = false; _mouseUpdate = false; if (inputEventTouchEnd != null) { inputEventTouchEnd.Raise(Input.mousePosition); } touchPosition = Input.mousePosition; } if (_mouseDown && _mouseUpdate) { if (inputEventTouchMove != null) { inputEventTouchMove.Raise(Input.mousePosition); } touchPosition = Input.mousePosition; } } } } ================================================ FILE: VirtueSky/TouchInput/Runtime/TouchInputManager.cs.meta ================================================ fileFormatVersion: 2 guid: c749a2fdea6f4e87b4cf5c41c5da0d2c MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 1c63e3b6583d6b54a8de6efcd2a86725, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/TouchInput/Runtime/Virtuesky.Sunflower.TouchInput.asmdef ================================================ { "name": "Virtuesky.Sunflower.TouchInput", "rootNamespace": "", "references": [ "GUID:acb3cac55c622ec459c8caadf707623a", "GUID:324caed91501a9c47a04ebfd87b68794", "GUID:bd40169efe8642149b1d2b72ba4903ce", "GUID:35d694408290717499b3838802212c7f" ], "includePlatforms": [], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], "versionDefines": [], "noEngineReferences": false } ================================================ FILE: VirtueSky/TouchInput/Runtime/Virtuesky.Sunflower.TouchInput.asmdef.meta ================================================ fileFormatVersion: 2 guid: fe2654b21280dcc4b8f7cff43f5cc40b AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/TouchInput/Runtime.meta ================================================ fileFormatVersion: 2 guid: f1cb1395cead95140be8aa6bcc771f2d folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/TouchInput.meta ================================================ fileFormatVersion: 2 guid: f16b4384183147518ca672ec7e42afb4 timeCreated: 1720080116 ================================================ FILE: VirtueSky/Tracking/Editor/TrackingWindowEditor.cs ================================================ using UnityEditor; using VirtueSky.Tracking; using VirtueSky.UtilsEditor; public class TrackingWindowEditor : EditorWindow { private const string pathFirebaseTracking = "/FirebaseAnalytic_Tracking"; private const string pathAdjustTracking = "/AdjustTracking"; private const string pathAppsFlyerTracking = "/AppsFlyerTracking"; #region Firebase Tracking // [MenuItem("Sunflower/Firebase Analytic/Log Event Firebase No Param")] public static void CreateLogEventFirebaseNoParam() { CreateAsset.CreateScriptableAssetsOnlyName( pathFirebaseTracking, "tracking_firebase_no_param"); } // [MenuItem("Sunflower/Firebase Analytic/Log Event Firebase 1 Param")] public static void CreateLogEventFirebaseOneParam() { CreateAsset.CreateScriptableAssetsOnlyName( pathFirebaseTracking, "tracking_firebase_1_param"); } // [MenuItem("Sunflower/Firebase Analytic/Log Event Firebase 2 Param")] public static void CreateLogEventFirebaseTwoParam() { CreateAsset.CreateScriptableAssetsOnlyName( pathFirebaseTracking, "tracking_firebase_2_param"); } //[MenuItem("Sunflower/Firebase Analytic/Log Event Firebase 3 Param")] public static void CreateLogEventFirebaseThreeParam() { CreateAsset.CreateScriptableAssetsOnlyName( pathFirebaseTracking, "tracking_firebase_3_param"); } //[MenuItem("Sunflower/Firebase Analytic/Log Event Firebase 4 Param")] public static void CreateLogEventFirebaseFourParam() { CreateAsset.CreateScriptableAssetsOnlyName( pathFirebaseTracking, "tracking_firebase_4_param"); } // [MenuItem("Sunflower/Firebase Analytic/Log Event Firebase 5 Param")] public static void CreateLogEventFirebaseFiveParam() { CreateAsset.CreateScriptableAssetsOnlyName( pathFirebaseTracking, "tracking_firebase_5_param"); } // [MenuItem("Sunflower/Firebase Analytic/Log Event Firebase 6 Param")] public static void CreateLogEventFirebaseSixParam() { CreateAsset.CreateScriptableAssetsOnlyName( pathFirebaseTracking, "tracking_firebase_6_param"); } #endregion #region AppsFlyer Tracking public static void CreateTrackingAfNoParam() { CreateAsset.CreateScriptableAssetsOnlyName(pathAppsFlyerTracking, "tracking_appsflyer_no_param"); } public static void CreateTrackingAf1Param() { CreateAsset.CreateScriptableAssetsOnlyName(pathAppsFlyerTracking, "tracking_appsflyer_1_param"); } public static void CreateTrackingAf2Param() { CreateAsset.CreateScriptableAssetsOnlyName(pathAppsFlyerTracking, "tracking_appsflyer_2_param"); } public static void CreateTrackingAf3Param() { CreateAsset.CreateScriptableAssetsOnlyName(pathAppsFlyerTracking, "tracking_appsflyer_3_param"); } public static void CreateTrackingAf4Param() { CreateAsset.CreateScriptableAssetsOnlyName(pathAppsFlyerTracking, "tracking_appsflyer_4_param"); } public static void CreateTrackingAf5Param() { CreateAsset.CreateScriptableAssetsOnlyName(pathAppsFlyerTracking, "tracking_appsflyer_5_param"); } public static void CreateTrackingAfHasParam() { CreateAsset.CreateScriptableAssetsOnlyName(pathAppsFlyerTracking, "tracking_appsflyer_has_param"); } #endregion public static void CreateTrackingAdjust() { CreateAsset.CreateScriptableAssetsOnlyName(pathAdjustTracking, "tracking_adjust"); } } ================================================ FILE: VirtueSky/Tracking/Editor/TrackingWindowEditor.cs.meta ================================================ fileFormatVersion: 2 guid: 1d6eaeb455d51d14bbb078ca4ad09a96 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Tracking/Editor/Virtuesky.Sunflower.TrackingEditor.asmdef ================================================ { "name": "Virtuesky.Sunflower.TrackingEditor", "rootNamespace": "", "references": [ "GUID:5e9107a8f2499184ea26564811dda246", "GUID:c904f6d969e991d459a0843b71c22ec5" ], "includePlatforms": [ "Editor" ], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], "versionDefines": [], "noEngineReferences": false } ================================================ FILE: VirtueSky/Tracking/Editor/Virtuesky.Sunflower.TrackingEditor.asmdef.meta ================================================ fileFormatVersion: 2 guid: ade1d0a32a74d554ab9bf506427a1b1b AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Tracking/Editor.meta ================================================ fileFormatVersion: 2 guid: e6c252b21ccd90b4a939ad50a69e29a9 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Tracking/Runtime/AdjustTracking/AdjustConfig.cs ================================================ #if VIRTUESKY_ADJUST using AdjustSdk; #endif using UnityEngine; using VirtueSky.Inspector; using VirtueSky.Utils; namespace VirtueSky.Tracking { [EditorIcon("icon_scriptable"), HideMonoScript] public class AdjustConfig : ScriptableSettings { [SerializeField] private string appToken; #if VIRTUESKY_ADJUST [SerializeField] private AdjustEnvironment adjustEnvironment = AdjustEnvironment.Production; [SerializeField] private AdjustLogLevel logLevel = AdjustLogLevel.Error; #endif public static string AppToken => Instance.appToken; #if VIRTUESKY_ADJUST public static AdjustEnvironment AdjustEnvironment => Instance.adjustEnvironment; public static AdjustLogLevel LogLevel => Instance.logLevel; #endif } } ================================================ FILE: VirtueSky/Tracking/Runtime/AdjustTracking/AdjustConfig.cs.meta ================================================ fileFormatVersion: 2 guid: 34657995523d4530bc6a14476a10a838 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: ed5ec0bb4ec55df47af0ecc2bd7be5f9, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Tracking/Runtime/AdjustTracking/AdjustTrackingRevenue.cs ================================================ using System; #if VIRTUESKY_ADJUST using AdjustSdk; #endif namespace VirtueSky.Tracking { public struct AdjustTrackingRevenue { public static Action OnTracked; public static void AdjustTrackRevenue(double value, string network, string unitId, string placement, string currentAdMediation) { #if VIRTUESKY_ADJUST var source = ""; switch (currentAdMediation.ToLower()) { case "admob": source = "admob_sdk"; break; case "applovin": source = "applovin_max_sdk"; break; case "levelplay": source = "levelplay_ironsource_sdk"; break; } AdjustAdRevenue adjustAdRevenue = new AdjustAdRevenue(source); adjustAdRevenue.SetRevenue(value, "USD"); adjustAdRevenue.AdRevenueNetwork = network; adjustAdRevenue.AdRevenueUnit = unitId; adjustAdRevenue.AdRevenuePlacement = placement; Adjust.TrackAdRevenue(adjustAdRevenue); OnTracked?.Invoke(); #endif } } } ================================================ FILE: VirtueSky/Tracking/Runtime/AdjustTracking/AdjustTrackingRevenue.cs.meta ================================================ fileFormatVersion: 2 guid: bebd00f793cf40c6a22d584bc0ea23dc timeCreated: 1704883003 ================================================ FILE: VirtueSky/Tracking/Runtime/AdjustTracking/TrackingAdjust.cs ================================================ using System; using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Tracking { [CreateAssetMenu(menuName = "Sunflower/Tracking Event/Adjust", fileName = "tracking_adjust")] [EditorIcon("scriptable_adjust2")] public class TrackingAdjust : ScriptableObject { [HeaderLine("Event Token"), SerializeField] private string eventToken; public static Action OnTracked; public void TrackEvent() { #if VIRTUESKY_ADJUST AdjustSdk.Adjust.TrackEvent(new AdjustSdk.AdjustEvent(eventToken)); OnTracked?.Invoke(); #endif } } } ================================================ FILE: VirtueSky/Tracking/Runtime/AdjustTracking/TrackingAdjust.cs.meta ================================================ fileFormatVersion: 2 guid: 669549b6839748409353138daa666c2f MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: b9157b0e91856514ba3f36deebb179cd, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Tracking/Runtime/AdjustTracking.meta ================================================ fileFormatVersion: 2 guid: e5b11169aa862d440836b218bc54a382 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Tracking/Runtime/AppTracking.cs ================================================ namespace VirtueSky.Tracking { public struct AppTracking { private static bool enableTrackRevenue; public static void Init(bool _enableTrackRevenue) { enableTrackRevenue = _enableTrackRevenue; } public static void TrackRevenue(double value, string network, string unitId, string format, string currentAdMediation) { if (!enableTrackRevenue) return; AdjustTrackingRevenue.AdjustTrackRevenue(value, network, unitId, format, currentAdMediation); FirebaseAnalyticTrackingRevenue.FirebaseAnalyticTrackRevenue(value, network, unitId, format, currentAdMediation); AppsFlyerTrackingRevenue.AppsFlyerTrackRevenueAd(value, network, unitId, format, currentAdMediation); } public static void FirebaseAnalyticTrackATTResult(int status) { #if VIRTUESKY_FIREBASE_ANALYTIC Firebase.Analytics.FirebaseAnalytics.LogEvent("app_tracking_transparency", "status", status); #endif } public static void StartTrackingAdjust() { #if VIRTUESKY_ADJUST var adjust = new UnityEngine.GameObject("Adjust", typeof(AdjustSdk.Adjust)); var adjustConfig = new AdjustSdk.AdjustConfig(AdjustConfig.AppToken, AdjustConfig.AdjustEnvironment, AdjustConfig.LogLevel == AdjustSdk.AdjustLogLevel.Suppress) { LogLevel = AdjustConfig.LogLevel, IsAdServicesEnabled = true, IsIdfaReadingEnabled = true }; AdjustSdk.Adjust.InitSdk(adjustConfig); UnityEngine.Debug.Log($"Start Tracking {adjust.name}"); #endif } public static void StartTrackingAppsFlyer() { #if VIRTUESKY_APPSFLYER var appFlyerObject = new UnityEngine.GameObject("AppsFlyerObject", typeof(VirtueSky.Tracking.AppsFlyerObject)); UnityEngine.Debug.Log($"Start Tracking {appFlyerObject.name}"); #endif } } } ================================================ FILE: VirtueSky/Tracking/Runtime/AppTracking.cs.meta ================================================ fileFormatVersion: 2 guid: 100aece4cce647fcac4bb39d00a7cd4c timeCreated: 1696404726 ================================================ FILE: VirtueSky/Tracking/Runtime/AppsFlyerTracking/AppsFlyerConfig.cs ================================================ using UnityEngine; using VirtueSky.Inspector; using VirtueSky.Utils; namespace VirtueSky.Tracking { [EditorIcon("icon_scriptable"), HideMonoScript] public class AppsFlyerConfig : ScriptableSettings { [SerializeField] private string devKey; [SerializeField] private string appID; [SerializeField] private string uwpAppID; [SerializeField] private string macOSAppID; [SerializeField] private bool getConversionData; [SerializeField] private bool isDebug; [SerializeField] private bool isDebugAdRevenue; public static string DevKey => Instance.devKey; public static string AppID => Instance.appID; public static string UWPAppID => Instance.uwpAppID; public static string MacOSAppID => Instance.macOSAppID; public static bool IsDebug => Instance.isDebug; public static bool IsDebugAdRevenue => Instance.isDebugAdRevenue; public static bool GetConversionData => Instance.getConversionData; } } ================================================ FILE: VirtueSky/Tracking/Runtime/AppsFlyerTracking/AppsFlyerConfig.cs.meta ================================================ fileFormatVersion: 2 guid: 7b91837cb644418dba77c9fd3ec09ec1 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: ed5ec0bb4ec55df47af0ecc2bd7be5f9, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Tracking/Runtime/AppsFlyerTracking/AppsFlyerObject.cs ================================================ #if VIRTUESKY_APPSFLYER using AppsFlyerSDK; #endif using System; using UnityEngine; namespace VirtueSky.Tracking { public class AppsFlyerObject : MonoBehaviour { private void Awake() { #if !UNITY_EDITOR DontDestroyOnLoad(this); #endif } private void Start() { #if VIRTUESKY_APPSFLYER // These fields are set from the editor so do not modify! //******************************// AppsFlyer.setIsDebug(AppsFlyerConfig.IsDebug); #if UNITY_WSA_10_0 && !UNITY_EDITOR AppsFlyer.initSDK(AppsFlyerSetting.DevKey, AppsFlyerSetting.UWPAppID, AppsFlyerSetting.GetConversionData ? this : null); #elif UNITY_STANDALONE_OSX && !UNITY_EDITOR AppsFlyer.initSDK(AppsFlyerSetting.DevKey, AppsFlyerSetting.MacOSAppID, AppsFlyerSetting.GetConversionData ? this : null); #else AppsFlyer.initSDK(AppsFlyerConfig.DevKey, AppsFlyerConfig.AppID, AppsFlyerConfig.GetConversionData ? this : null); #endif //******************************/ AppsFlyer.startSDK(); #endif } } } ================================================ FILE: VirtueSky/Tracking/Runtime/AppsFlyerTracking/AppsFlyerObject.cs.meta ================================================ fileFormatVersion: 2 guid: a110a1c48939450aa0b0517c5ccd7f1b timeCreated: 1723541286 ================================================ FILE: VirtueSky/Tracking/Runtime/AppsFlyerTracking/AppsFlyerTrackingRevenue.cs ================================================ using System; using System.Collections.Generic; #if VIRTUESKY_APPSFLYER using AppsFlyerSDK; #endif #if VIRTUESKY_IAP using UnityEngine.Purchasing; #endif namespace VirtueSky.Tracking { public struct AppsFlyerTrackingRevenue { public static Action OnTracked; public static void AppsFlyerTrackRevenueAd(double value, string network, string unitId, string format, string currentAdMediation) { #if VIRTUESKY_APPSFLYER var mediationNetworks = MediationNetwork.GoogleAdMob; switch (currentAdMediation.ToLower()) { case "admob": mediationNetworks = MediationNetwork.GoogleAdMob; break; case "applovin": mediationNetworks = MediationNetwork.ApplovinMax; break; case "levelplay": mediationNetworks = MediationNetwork.IronSource; break; } Dictionary additionalParams = new Dictionary(); additionalParams.Add(AdRevenueScheme.COUNTRY, "US"); additionalParams.Add(AdRevenueScheme.AD_UNIT, unitId); additionalParams.Add(AdRevenueScheme.AD_TYPE, format); AppsFlyer.logAdRevenue(new AFAdRevenueData(network, mediationNetworks, "USD", value), additionalParams); OnTracked?.Invoke(); #endif } #if VIRTUESKY_APPSFLYER && VIRTUESKY_IAP public static void AppFlyerTrackingRevenueInAppPurchase(Product product) { Dictionary eventValue = new Dictionary(); eventValue.Add("af_revenue", GetAppsflyerRevenue(product.metadata.localizedPrice)); eventValue.Add("af_content_id", product.definition.id); eventValue.Add("af_currency", product.metadata.isoCurrencyCode); AppsFlyer.sendEvent("af_purchase", eventValue); } public static string GetAppsflyerRevenue(decimal amount) { decimal val = decimal.Multiply(amount, 0.63m); return val.ToString(); } #endif } } ================================================ FILE: VirtueSky/Tracking/Runtime/AppsFlyerTracking/AppsFlyerTrackingRevenue.cs.meta ================================================ fileFormatVersion: 2 guid: 4e397132c1af4396bc9609457c04e02a timeCreated: 1704883287 ================================================ FILE: VirtueSky/Tracking/Runtime/AppsFlyerTracking/TrackingAppsFlyer.cs ================================================ using System; using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Tracking { public abstract class TrackingAppsFlyer : ScriptableObject { [Space, HeaderLine("Event Name"), SerializeField] protected string eventName; protected Action onTracked; public event Action OnTracked { add => onTracked += value; remove => onTracked -= value; } } } ================================================ FILE: VirtueSky/Tracking/Runtime/AppsFlyerTracking/TrackingAppsFlyer.cs.meta ================================================ fileFormatVersion: 2 guid: 9598a59ad0b34a31a20817d3aa99c4f0 timeCreated: 1728964263 ================================================ FILE: VirtueSky/Tracking/Runtime/AppsFlyerTracking/TrackingAppsFlyerFiveParam.cs ================================================ using System.Collections.Generic; using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Tracking { [CreateAssetMenu(menuName = "Sunflower/Tracking Event/AppsFlyer/Tracking 5 Param", fileName = "tracking_appsflyer_5_param")] [EditorIcon("scriptable_af")] public class TrackingAppsFlyerFiveParam : TrackingAppsFlyer { [Space, HeaderLine("Parameter Name"), SerializeField] private string parameterName1; [SerializeField] private string parameterName2; [SerializeField] private string parameterName3; [SerializeField] private string parameterName4; [SerializeField] private string parameterName5; public void TrackEvent(string parameterValue1, string parameterValue2, string parameterValue3, string parameterValue4, string parameterValue5) { #if VIRTUESKY_APPSFLYER Dictionary eventValues = new Dictionary(); eventValues.Add(parameterName1, parameterValue1); eventValues.Add(parameterName2, parameterValue2); eventValues.Add(parameterName3, parameterValue3); eventValues.Add(parameterName4, parameterValue4); eventValues.Add(parameterName5, parameterValue5); AppsFlyerSDK.AppsFlyer.sendEvent(eventName, eventValues); onTracked?.Invoke(); #endif } } } ================================================ FILE: VirtueSky/Tracking/Runtime/AppsFlyerTracking/TrackingAppsFlyerFiveParam.cs.meta ================================================ fileFormatVersion: 2 guid: 0706da9436ff406ba4cba1c0ce0f8a34 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 923d17c486919a945a5fef5ca1ee8e9b, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Tracking/Runtime/AppsFlyerTracking/TrackingAppsFlyerFourParam.cs ================================================ using System.Collections.Generic; using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Tracking { [CreateAssetMenu(menuName = "Sunflower/Tracking Event/AppsFlyer/Tracking 4 Param", fileName = "tracking_appsflyer_4_param")] [EditorIcon("scriptable_af")] public class TrackingAppsFlyerFourParam : TrackingAppsFlyer { [Space, HeaderLine("Parameter Name"), SerializeField] private string parameterName1; [SerializeField] private string parameterName2; [SerializeField] private string parameterName3; [SerializeField] private string parameterName4; public void TrackEvent(string parameterValue1, string parameterValue2, string parameterValue3, string parameterValue4) { #if VIRTUESKY_APPSFLYER Dictionary eventValues = new Dictionary(); eventValues.Add(parameterName1, parameterValue1); eventValues.Add(parameterName2, parameterValue2); eventValues.Add(parameterName3, parameterValue3); eventValues.Add(parameterName4, parameterValue4); AppsFlyerSDK.AppsFlyer.sendEvent(eventName, eventValues); onTracked?.Invoke(); #endif } } } ================================================ FILE: VirtueSky/Tracking/Runtime/AppsFlyerTracking/TrackingAppsFlyerFourParam.cs.meta ================================================ fileFormatVersion: 2 guid: 4b2796bc39ac4335890159d6a5758a51 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 923d17c486919a945a5fef5ca1ee8e9b, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Tracking/Runtime/AppsFlyerTracking/TrackingAppsFlyerHasParam.cs ================================================ using System.Collections; using System.Collections.Generic; using UnityEngine; using VirtueSky.Inspector; using VirtueSky.Misc; namespace VirtueSky.Tracking { [CreateAssetMenu(menuName = "Sunflower/Tracking Event/AppsFlyer/Tracking Has Param", fileName = "tracking_appsflyer_has_param")] [EditorIcon("scriptable_af")] public class TrackingAppsFlyerHasParam : TrackingAppsFlyer { public void TrackEvent(Dictionary eventValues) { #if VIRTUESKY_APPSFLYER AppsFlyerSDK.AppsFlyer.sendEvent(eventName, eventValues); #endif } public void TrackEvent(List paramNames, List paramValues) { #if VIRTUESKY_APPSFLYER IDictionary eventValues = paramNames.MakeDictionary(paramValues); AppsFlyerSDK.AppsFlyer.sendEvent(eventName, (Dictionary)eventValues); onTracked?.Invoke(); #endif } } } ================================================ FILE: VirtueSky/Tracking/Runtime/AppsFlyerTracking/TrackingAppsFlyerHasParam.cs.meta ================================================ fileFormatVersion: 2 guid: 669a290e920a4cf3878a06a85ba37fa0 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 923d17c486919a945a5fef5ca1ee8e9b, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Tracking/Runtime/AppsFlyerTracking/TrackingAppsFlyerNoParam.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Tracking { [CreateAssetMenu(menuName = "Sunflower/Tracking Event/AppsFlyer/Tracking No Param", fileName = "tracking_appsflyer_no_param")] [EditorIcon("scriptable_af")] public class TrackingAppsFlyerNoParam : TrackingAppsFlyer { public void TrackEvent() { #if VIRTUESKY_APPSFLYER AppsFlyerSDK.AppsFlyer.sendEvent(eventName, null); onTracked?.Invoke(); #endif } } } ================================================ FILE: VirtueSky/Tracking/Runtime/AppsFlyerTracking/TrackingAppsFlyerNoParam.cs.meta ================================================ fileFormatVersion: 2 guid: a113e27321fd46b59e8d12c1707ffe10 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 923d17c486919a945a5fef5ca1ee8e9b, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Tracking/Runtime/AppsFlyerTracking/TrackingAppsFlyerOneParam.cs ================================================ using System.Collections.Generic; using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Tracking { [CreateAssetMenu(menuName = "Sunflower/Tracking Event/AppsFlyer/Tracking 1 Param", fileName = "tracking_appsflyer_1_param")] [EditorIcon("scriptable_af")] public class TrackingAppsFlyerOneParam : TrackingAppsFlyer { [Space, HeaderLine("Parameter Name"), SerializeField] private string parameterName; public void TrackEvent(string parameterValue) { #if VIRTUESKY_APPSFLYER Dictionary eventValues = new Dictionary(); eventValues.Add(parameterName, parameterValue); AppsFlyerSDK.AppsFlyer.sendEvent(eventName, eventValues); onTracked?.Invoke(); #endif } } } ================================================ FILE: VirtueSky/Tracking/Runtime/AppsFlyerTracking/TrackingAppsFlyerOneParam.cs.meta ================================================ fileFormatVersion: 2 guid: 4d8f7c3b324d4297bf68a2072f9c4f90 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 923d17c486919a945a5fef5ca1ee8e9b, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Tracking/Runtime/AppsFlyerTracking/TrackingAppsFlyerThreeParam.cs ================================================ using System.Collections.Generic; using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Tracking { [CreateAssetMenu(menuName = "Sunflower/Tracking Event/AppsFlyer/Tracking 3 Param", fileName = "tracking_appsflyer_3_param")] [EditorIcon("scriptable_af")] public class TrackingAppsFlyerThreeParam : TrackingAppsFlyer { [Space, HeaderLine("Parameter Name"), SerializeField] private string parameterName1; [SerializeField] private string parameterName2; [SerializeField] private string parameterName3; public void TrackEvent(string parameterValue1, string parameterValue2, string parameterValue3) { #if VIRTUESKY_APPSFLYER Dictionary eventValues = new Dictionary(); eventValues.Add(parameterName1, parameterValue1); eventValues.Add(parameterName2, parameterValue2); eventValues.Add(parameterName3, parameterValue3); AppsFlyerSDK.AppsFlyer.sendEvent(eventName, eventValues); onTracked?.Invoke(); #endif } } } ================================================ FILE: VirtueSky/Tracking/Runtime/AppsFlyerTracking/TrackingAppsFlyerThreeParam.cs.meta ================================================ fileFormatVersion: 2 guid: f011e56fe795441db526d34550e913ef MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 923d17c486919a945a5fef5ca1ee8e9b, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Tracking/Runtime/AppsFlyerTracking/TrackingAppsFlyerTwoParam.cs ================================================ using System.Collections.Generic; using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Tracking { [CreateAssetMenu(menuName = "Sunflower/Tracking Event/AppsFlyer/Tracking 2 Param", fileName = "tracking_appsflyer_2_param")] [EditorIcon("scriptable_af")] public class TrackingAppsFlyerTwoParam : TrackingAppsFlyer { [Space, HeaderLine("Parameter Name"), SerializeField] private string parameterName1; [SerializeField] private string parameterName2; public void TrackEvent(string parameterValue1, string parameterValue2) { #if VIRTUESKY_APPSFLYER Dictionary eventValues = new Dictionary(); eventValues.Add(parameterName1, parameterValue1); eventValues.Add(parameterName2, parameterValue2); AppsFlyerSDK.AppsFlyer.sendEvent(eventName, eventValues); onTracked?.Invoke(); #endif } } } ================================================ FILE: VirtueSky/Tracking/Runtime/AppsFlyerTracking/TrackingAppsFlyerTwoParam.cs.meta ================================================ fileFormatVersion: 2 guid: 214872ae9c29427280cb8d1536053c22 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 923d17c486919a945a5fef5ca1ee8e9b, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Tracking/Runtime/AppsFlyerTracking.meta ================================================ fileFormatVersion: 2 guid: a8a61d961531cba4fb2a06c2fe643354 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Tracking/Runtime/FirebaseAnalyticTracking/FirebaseAnalyticTrackingRevenue.cs ================================================ using System; #if VIRTUESKY_FIREBASE_ANALYTIC using Firebase.Analytics; #endif namespace VirtueSky.Tracking { public struct FirebaseAnalyticTrackingRevenue { public static Action OnTracked; public static bool autoTrackAdImpressionAdmob; public static void FirebaseAnalyticTrackRevenue(double value, string network, string unitId, string format, string currentAdMediation) { #if VIRTUESKY_FIREBASE_ANALYTIC string ad_platform = ""; switch (currentAdMediation.ToLower()) { case "admob": if (autoTrackAdImpressionAdmob) return; ad_platform = "Admob"; break; case "applovin": ad_platform = "AppLovin"; break; case "levelplay": ad_platform = "IronSource"; break; } Parameter[] parameters = { new("value", value), new("ad_platform", ad_platform), new("ad_format", format), new("currency", "USD"), new("ad_unit_id", unitId), new("ad_source", network) }; FirebaseAnalytics.LogEvent("ad_impression", parameters); OnTracked?.Invoke(); #endif } } } ================================================ FILE: VirtueSky/Tracking/Runtime/FirebaseAnalyticTracking/FirebaseAnalyticTrackingRevenue.cs.meta ================================================ fileFormatVersion: 2 guid: 0e69053dd6f04bdb836b272966506c95 timeCreated: 1704882713 ================================================ FILE: VirtueSky/Tracking/Runtime/FirebaseAnalyticTracking/TrackingFirebase.cs ================================================ using System; using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Tracking { public abstract class TrackingFirebase : ScriptableObject { [Space] [HeaderLine("Event Name")] [SerializeField] protected string eventName; protected Action onTracked; public event Action OnTracked { add => onTracked += value; remove => onTracked -= value; } } } ================================================ FILE: VirtueSky/Tracking/Runtime/FirebaseAnalyticTracking/TrackingFirebase.cs.meta ================================================ fileFormatVersion: 2 guid: 02a2b0817bed4feabe60b33ab8bf18fd timeCreated: 1728963039 ================================================ FILE: VirtueSky/Tracking/Runtime/FirebaseAnalyticTracking/TrackingFirebaseFiveParam.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Tracking { [CreateAssetMenu(menuName = "Sunflower/Tracking Event/Firebase Analytic/Tracking 5 Param", fileName = "tracking_firebase_5_param")] [EditorIcon("scriptable_firebase")] public class TrackingFirebaseFiveParam : TrackingFirebase { [Space] [HeaderLine("Parameter Name")] [SerializeField] private string parameterName1; [SerializeField] private string parameterName2; [SerializeField] private string parameterName3; [SerializeField] private string parameterName4; [SerializeField] private string parameterName5; public void TrackEvent(string parameterValue1, string parameterValue2, string parameterValue3, string parameterValue4, string parameterValue5) { if (!Application.isMobilePlatform) return; #if VIRTUESKY_FIREBASE_ANALYTIC Firebase.Analytics.Parameter[] parameters = { new(parameterName1, parameterValue1), new(parameterName2, parameterValue2), new(parameterName3, parameterValue3), new(parameterName4, parameterValue4), new(parameterName5, parameterValue5) }; Firebase.Analytics.FirebaseAnalytics.LogEvent(eventName, parameters); onTracked?.Invoke(); #endif } } } ================================================ FILE: VirtueSky/Tracking/Runtime/FirebaseAnalyticTracking/TrackingFirebaseFiveParam.cs.meta ================================================ fileFormatVersion: 2 guid: f6c32ba92556429096a143e9146cb9fe MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: c1bc3702a7695674fbddba3cae1c2a78, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Tracking/Runtime/FirebaseAnalyticTracking/TrackingFirebaseFourParam.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Tracking { [CreateAssetMenu(menuName = "Sunflower/Tracking Event/Firebase Analytic/Tracking 4 Param", fileName = "tracking_firebase_4_param")] [EditorIcon("scriptable_firebase")] public class TrackingFirebaseFourParam : TrackingFirebase { [Space] [HeaderLine("Parameter Name")] [SerializeField] private string parameterName1; [SerializeField] private string parameterName2; [SerializeField] private string parameterName3; [SerializeField] private string parameterName4; public void TrackEvent(string parameterValue1, string parameterValue2, string parameterValue3, string parameterValue4) { if (!Application.isMobilePlatform) return; #if VIRTUESKY_FIREBASE_ANALYTIC Firebase.Analytics.Parameter[] parameters = { new(parameterName1, parameterValue1), new(parameterName2, parameterValue2), new(parameterName3, parameterValue3), new(parameterName4, parameterValue4) }; Firebase.Analytics.FirebaseAnalytics.LogEvent(eventName, parameters); onTracked?.Invoke(); #endif } } } ================================================ FILE: VirtueSky/Tracking/Runtime/FirebaseAnalyticTracking/TrackingFirebaseFourParam.cs.meta ================================================ fileFormatVersion: 2 guid: d3118516a2474dfbafd5f776dfdd3312 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: c1bc3702a7695674fbddba3cae1c2a78, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Tracking/Runtime/FirebaseAnalyticTracking/TrackingFirebaseNoParam.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Tracking { [CreateAssetMenu(menuName = "Sunflower/Tracking Event/Firebase Analytic/Tracking No Param", fileName = "tracking_firebase_no_param")] [EditorIcon("scriptable_firebase")] public class TrackingFirebaseNoParam : TrackingFirebase { public void TrackEvent() { if (!Application.isMobilePlatform) return; #if VIRTUESKY_FIREBASE_ANALYTIC Firebase.Analytics.FirebaseAnalytics.LogEvent(eventName); onTracked?.Invoke(); #endif } } } ================================================ FILE: VirtueSky/Tracking/Runtime/FirebaseAnalyticTracking/TrackingFirebaseNoParam.cs.meta ================================================ fileFormatVersion: 2 guid: f7a9cb05e507c704597bcb479279eb59 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: c1bc3702a7695674fbddba3cae1c2a78, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Tracking/Runtime/FirebaseAnalyticTracking/TrackingFirebaseOneParam.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Tracking { [CreateAssetMenu(menuName = "Sunflower/Tracking Event/Firebase Analytic/Tracking 1 Param", fileName = "tracking_firebase_1_param")] [EditorIcon("scriptable_firebase")] public class TrackingFirebaseOneParam : TrackingFirebase { [Space] [HeaderLine("Parameter Name")] [SerializeField] private string parameterName; public void TrackEvent(string parameterValue) { if (!Application.isMobilePlatform) return; #if VIRTUESKY_FIREBASE_ANALYTIC Firebase.Analytics.FirebaseAnalytics.LogEvent(eventName, parameterName, parameterValue); onTracked?.Invoke(); #endif } } } ================================================ FILE: VirtueSky/Tracking/Runtime/FirebaseAnalyticTracking/TrackingFirebaseOneParam.cs.meta ================================================ fileFormatVersion: 2 guid: e8b5edc0caef4a02a234b4d36a5a1c2a MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: c1bc3702a7695674fbddba3cae1c2a78, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Tracking/Runtime/FirebaseAnalyticTracking/TrackingFirebaseSixParam.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Tracking { [CreateAssetMenu(menuName = "Sunflower/Tracking Event/Firebase Analytic/Tracking 6 Param", fileName = "tracking_firebase_6_param")] [EditorIcon("scriptable_firebase")] public class TrackingFirebaseSixParam : TrackingFirebase { [Space] [HeaderLine("Parameter Name")] [SerializeField] private string parameterName1; [SerializeField] private string parameterName2; [SerializeField] private string parameterName3; [SerializeField] private string parameterName4; [SerializeField] private string parameterName5; [SerializeField] private string parameterName6; public void TrackEvent(string parameterValue1, string parameterValue2, string parameterValue3, string parameterValue4, string parameterValue5, string parameterValue6) { if (!Application.isMobilePlatform) return; #if VIRTUESKY_FIREBASE_ANALYTIC Firebase.Analytics.Parameter[] parameters = { new(parameterName1, parameterValue1), new(parameterName2, parameterValue2), new(parameterName3, parameterValue3), new(parameterName4, parameterValue4), new(parameterName5, parameterValue5), new(parameterName6, parameterValue6) }; Firebase.Analytics.FirebaseAnalytics.LogEvent(eventName, parameters); onTracked?.Invoke(); #endif } } } ================================================ FILE: VirtueSky/Tracking/Runtime/FirebaseAnalyticTracking/TrackingFirebaseSixParam.cs.meta ================================================ fileFormatVersion: 2 guid: d9ec77fca5e440daad87cb6d75e5cbbc MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: c1bc3702a7695674fbddba3cae1c2a78, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Tracking/Runtime/FirebaseAnalyticTracking/TrackingFirebaseThreeParam.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Tracking { [CreateAssetMenu(menuName = "Sunflower/Tracking Event/Firebase Analytic/Tracking 3 Param", fileName = "tracking_firebase_3_param")] [EditorIcon("scriptable_firebase")] public class TrackingFirebaseThreeParam : TrackingFirebase { [Space] [HeaderLine("Parameter Name")] [SerializeField] private string parameterName1; [SerializeField] private string parameterName2; [SerializeField] private string parameterName3; public void TrackEvent(string parameterValue1, string parameterValue2, string parameterValue3) { if (!Application.isMobilePlatform) return; #if VIRTUESKY_FIREBASE_ANALYTIC Firebase.Analytics.Parameter[] parameters = { new(parameterName1, parameterValue1), new(parameterName2, parameterValue2), new(parameterName3, parameterValue3) }; Firebase.Analytics.FirebaseAnalytics.LogEvent(eventName, parameters); onTracked?.Invoke(); #endif } } } ================================================ FILE: VirtueSky/Tracking/Runtime/FirebaseAnalyticTracking/TrackingFirebaseThreeParam.cs.meta ================================================ fileFormatVersion: 2 guid: 65f9fd1025e84ca58cd02e67f20b989c MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: c1bc3702a7695674fbddba3cae1c2a78, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Tracking/Runtime/FirebaseAnalyticTracking/TrackingFirebaseTwoParam.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Tracking { [CreateAssetMenu(menuName = "Sunflower/Tracking Event/Firebase Analytic/Tracking 2 Param", fileName = "tracking_firebase_2_param")] [EditorIcon("scriptable_firebase")] public class TrackingFirebaseTwoParam : TrackingFirebase { [Space] [HeaderLine("Parameter Name")] [SerializeField] private string parameterName1; [SerializeField] private string parameterName2; public void TrackEvent(string parameterValue1, string parameterValue2) { if (!Application.isMobilePlatform) return; #if VIRTUESKY_FIREBASE_ANALYTIC Firebase.Analytics.Parameter[] parameters = { new(parameterName1, parameterValue1), new(parameterName2, parameterValue2) }; Firebase.Analytics.FirebaseAnalytics.LogEvent(eventName, parameters); onTracked?.Invoke(); #endif } } } ================================================ FILE: VirtueSky/Tracking/Runtime/FirebaseAnalyticTracking/TrackingFirebaseTwoParam.cs.meta ================================================ fileFormatVersion: 2 guid: d48f930dfff944e4a740819da6d4a9da MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: c1bc3702a7695674fbddba3cae1c2a78, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Tracking/Runtime/FirebaseAnalyticTracking.meta ================================================ fileFormatVersion: 2 guid: 955e298e200b89b438b7adb5defe0e95 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Tracking/Runtime/Virtuesky.Sunflower.Tracking.asmdef ================================================ { "name": "Virtuesky.Sunflower.Tracking", "rootNamespace": "", "references": [ "VirtueSky.Sunflower.Inspector", "AppsFlyer", "Virtuesky.Sunflower.Misc", "Virtuesky.Sunflower.Utils", "AdjustSdk.Scripts", "Unity.Purchasing" ], "includePlatforms": [], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], "versionDefines": [], "noEngineReferences": false } ================================================ FILE: VirtueSky/Tracking/Runtime/Virtuesky.Sunflower.Tracking.asmdef.meta ================================================ fileFormatVersion: 2 guid: 5e9107a8f2499184ea26564811dda246 AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Tracking/Runtime.meta ================================================ fileFormatVersion: 2 guid: e17d26aa88d483a47b93fb2a35b75a91 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Tracking.meta ================================================ fileFormatVersion: 2 guid: 4e44f6988aead354092ac83733426b60 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/ConstantDefineSymbols.cs ================================================ namespace VirtueSky.UtilsEditor { public class ConstantDefineSymbols { public const string VIRTUESKY_ADS = "VIRTUESKY_ADS"; public const string VIRTUESKY_APPLOVIN = "VIRTUESKY_APPLOVIN"; public const string VIRTUESKY_ADMOB = "VIRTUESKY_ADMOB"; public const string VIRTUESKY_LEVELPLAY = "VIRTUESKY_LEVELPLAY"; public const string VIRTUESKY_ADJUST = "VIRTUESKY_ADJUST"; public const string VIRTUESKY_FIREBASE_ANALYTIC = "VIRTUESKY_FIREBASE_ANALYTIC"; public const string VIRTUESKY_FIREBASE_REMOTECONFIG = "VIRTUESKY_FIREBASE_REMOTECONFIG"; public const string VIRTUESKY_FIREBASE = "VIRTUESKY_FIREBASE"; public const string VIRTUESKY_IAP = "VIRTUESKY_IAP"; public const string VIRTUESKY_RATING = "VIRTUESKY_RATING"; public const string VIRTUESKY_NOTIFICATION = "VIRTUESKY_NOTIFICATION"; public const string VIRTUESKY_APPSFLYER = "VIRTUESKY_APPSFLYER"; public const string PRIME_TWEEN_DOTWEEN_ADAPTER = "PRIME_TWEEN_DOTWEEN_ADAPTER"; public const string PRIME_TWEEN_SAFETY_CHECKS = "PRIME_TWEEN_SAFETY_CHECKS"; public const string VIRTUESKY_GPGS = "VIRTUESKY_GPGS"; public const string VIRTUESKY_APPLE_AUTH = "VIRTUESKY_APPLE_AUTH"; public const string VIRTUESKY_SKELETON = "VIRTUESKY_SKELETON"; public const string VIRTUESKY_ANIMANCER = "VIRTUESKY_ANIMANCER"; public const string UNITASK_ADDRESSABLE_SUPPORT = "UNITASK_ADDRESSABLE_SUPPORT"; public const string UNITASK_DOTWEEN_SUPPORT = "UNITASK_DOTWEEN_SUPPORT"; public const string UNITASK_TEXTMESHPRO_SUPPORT = "UNITASK_TEXTMESHPRO_SUPPORT"; public const string VIRTUESKY_BAKINGSHEET = "VIRTUESKY_BAKINGSHEET"; public const string VIRTUESKY_UNITY_SERVICES = "VIRTUESKY_UNITY_SERVICES"; public const string ASSET_FINDER_ADDRESSABLE = "AssetFinderADDRESSABLE"; } } ================================================ FILE: VirtueSky/Utils/Editor/ConstantDefineSymbols.cs.meta ================================================ fileFormatVersion: 2 guid: 6dcba35e0a7aa644c932401834c3a8ed MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/CreateAsset.cs ================================================ using System.IO; using VirtueSky.Linq; using UnityEditor; using UnityEngine; namespace VirtueSky.UtilsEditor { public static class CreateAsset { #if UNITY_EDITOR public static T CreateScriptableAssets(string path = "", bool isPingAsset = true, bool useDefaultPath = true) where T : ScriptableObject { var setting = UnityEngine.ScriptableObject.CreateInstance(); UnityEditor.AssetDatabase.CreateAsset(setting, $"{DefaultPath(path, useDefaultPath)}/{typeof(T).Name}.asset"); UnityEditor.AssetDatabase.SaveAssets(); UnityEditor.AssetDatabase.Refresh(); Selection.activeObject = setting; if (isPingAsset) { EditorGUIUtility.PingObject(setting); } Debug.Log( $"{typeof(T).Name} was created ad {DefaultPath(path, useDefaultPath)}/{typeof(T).Name}.asset"); return setting; } public static T CreateScriptableAssets(string path = "", string name = "", bool isPingAsset = true, bool useDefaultPath = true) where T : ScriptableObject { string newName = name == "" ? typeof(T).Name : name; var setting = UnityEngine.ScriptableObject.CreateInstance(); UnityEditor.AssetDatabase.CreateAsset(setting, $"{DefaultPath(path, useDefaultPath)}/{newName}.asset"); UnityEditor.AssetDatabase.SaveAssets(); UnityEditor.AssetDatabase.Refresh(); Selection.activeObject = setting; if (isPingAsset) { EditorGUIUtility.PingObject(setting); } Debug.Log( $"{newName} was created ad {DefaultPath(path, useDefaultPath)}/{newName}.asset"); return setting; } public static T CreateScriptableAssetsOnlyName(string path = "", string name = "", bool isPingAsset = true, bool useDefaultPath = true) where T : ScriptableObject { int assetCounter = 0; string assetName = name == "" ? $"{typeof(T).Name}" : name; string assetPath = $"{DefaultPath(path, useDefaultPath)}/{assetName}.asset"; while (AssetDatabase.LoadAssetAtPath(assetPath) != null) { assetCounter++; assetPath = $"{DefaultPath(path)}/{CreateNameBasedOnGameObjectNamingScheme(assetName, assetCounter)}.asset"; } var setting = ScriptableObject.CreateInstance(); UnityEditor.AssetDatabase.CreateAsset(setting, assetPath); UnityEditor.AssetDatabase.SaveAssets(); UnityEditor.AssetDatabase.Refresh(); Selection.activeObject = setting; if (isPingAsset) { EditorGUIUtility.PingObject(setting); } Debug.Log( $"{typeof(T).Name} was created at {assetPath}"); return setting; } public static T CreateAndGetScriptableAsset(string path = "", string assetName = "", bool isPingAsset = true, bool useDefaultPath = true) where T : ScriptableObject { var so = GetScriptableAsset(); if (so == null) { CreateScriptableAssets(path, assetName, isPingAsset, useDefaultPath); so = GetScriptableAsset(); } return so; } public static T CreateAndGetScriptableAssetByName(string path = "", string assetName = "", bool isPingAsset = true, bool useDefaultPath = true) where T : ScriptableObject { var so = GetScriptableAssetByName(assetName); if (so == null) { CreateScriptableAssets(path, assetName, isPingAsset, useDefaultPath); so = GetScriptableAssetByName(assetName); } return so; } public static T GetScriptableAsset() where T : ScriptableObject { return FileExtension.FindAssetAtFolder(new string[] { "Assets" }).FirstOrDefault(); } public static T GetScriptableAssetByName(string name) where T : ScriptableObject { var arr = FileExtension.FindAssetAtFolder(new string[] { "Assets" }); foreach (var asset in arr) { if (asset.name == name) return asset; } return null; } // public enum NamingScheme // { // /// // /// Adds a space and a number in parenthesis to the name of an instantiated or duplicated GameObject ("Prefab (1)"). // /// // SpaceParenthesis, // /// // /// Adds a dot followed by a number to the name of an instantiated or duplicated GameObject ("Prefab.1"). // /// // Dot, // /// // /// Adds an underscore and a number to the name of an instantiated or duplicated GameObject ("Prefab_1"). // /// // Underscore, // } private static string CreateNameBasedOnGameObjectNamingScheme(string baseName, int counter) { EditorSettings.NamingScheme currentNamingScheme = EditorSettings.gameObjectNamingScheme; return currentNamingScheme switch { EditorSettings.NamingScheme.SpaceParenthesis => $"{baseName} ({counter})", EditorSettings.NamingScheme.Dot => $"{baseName}.{counter}", EditorSettings.NamingScheme.Underscore => $"{baseName}_{counter}", _ => $"{baseName} ({counter})" }; } #endif public static string DefaultPath(string path = "", bool useDefaultPath = true) { if (useDefaultPath) { const string defaultPath = "Assets/_Sunflower/Scriptable"; ValidatePath(defaultPath + path); return defaultPath + path; } ValidatePath(path); return path; } public static void ValidatePath(string path) { if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } } } } ================================================ FILE: VirtueSky/Utils/Editor/CreateAsset.cs.meta ================================================ fileFormatVersion: 2 guid: cdadc765aa5c5be4b9bb188ba0701a4c MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/EditorCoroutine.cs ================================================ using System; using System.Collections; using System.Collections.Generic; using System.Reflection; using UnityEditor; using UnityEngine; namespace VirtueSky.UtilsEditor { /// /// Represents a coroutine that has been started running in the editor. /// /// Also offers static methods for starting and stopping coroutines. /// /// public sealed class EditorCoroutine : YieldInstruction { public static event Action Stopped; private static readonly List Running = new(1); private static readonly FieldInfo WaitForSecondsSecondsField; private static readonly MethodInfo InvokeCompletionEventMethod; private readonly Stack _yielding = new(1); private double _waitUntil; public bool IsFinished => _yielding.Count == 0; static EditorCoroutine() { WaitForSecondsSecondsField = typeof(WaitForSeconds).GetField("m_Seconds", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); if (WaitForSecondsSecondsField is null) Debug.LogWarning("Field WaitForSeconds.m_Seconds not found."); InvokeCompletionEventMethod = typeof(AsyncOperation).GetMethod("InvokeCompletionEvent", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); if (InvokeCompletionEventMethod is null) Debug.LogWarning("Method AsyncOperation.InvokeCompletionEvent not found."); } private EditorCoroutine(IEnumerator routine) => _yielding.Push(routine); /// /// Starts the provided . /// /// The coroutine to start. /// /// A reference to the started . /// /// This reference can be passed to to stop /// the execution of the coroutine. /// /// public static EditorCoroutine Start(IEnumerator coroutine) { if (Running.Count == 0) EditorApplication.update += UpdateRunningCoroutines; var editorCoroutine = new EditorCoroutine(coroutine); Running.Add(editorCoroutine); return editorCoroutine; } /// /// Stops the coroutine that is running in edit mode. /// public void Stop() { Running.Remove(this); if (Running.Count == 0) EditorApplication.update -= UpdateRunningCoroutines; Stopped?.Invoke(this); } /// /// Stops the that is running. /// /// The coroutine to stop. public static void Stop(IEnumerator coroutine) { foreach (var editorCoroutine in Running) { int counter = editorCoroutine._yielding.Count; foreach (object item in editorCoroutine._yielding) { if (counter == 1 && item == coroutine) { editorCoroutine.Stop(); return; } counter--; } } } /// /// Stops all coroutines that have been started using that are currently still running. /// public static void StopAll() { Running.Clear(); EditorApplication.update -= UpdateRunningCoroutines; } /// /// Continuously advances all currently running coroutines to their /// next phases until all of them have reached the end. /// /// Note that this locks the current thread until all running coroutines have fully finished. /// If any coroutine contains CustomYieldInstructions /// that take a long time to finish (or never finish in edit mode) this can cause the editor /// to freeze for the same duration. /// /// public static void MoveAllToEnd() { int count = Running.Count; while (count > 0) { for (int i = count - 1; i >= 0; i--) { Running[i].MoveNext(true); } count = Running.Count; } } /// /// Advances all currently running coroutine to their next phase. /// /// /// (Optional) If then yield instructions /// and are skipped. /// /// if any coroutines are still running, if all have finished. public static bool MoveAllNext(bool skipWaits = false) { for (int i = Running.Count - 1; i >= 0; i--) { Running[i].MoveNext(skipWaits); } return Running.Count > 0; } private static void UpdateRunningCoroutines() { for (int i = Running.Count - 1; i >= 0; i--) { Running[i].MoveNext(); } } /// /// Advances the coroutine to the next phase. /// /// /// (Optional) If then yield instructions /// and are skipped. /// /// if coroutine is still running, if it has finished. public bool MoveNext(bool skipWaits = false) { if (EditorApplication.timeSinceStartup < _waitUntil && !skipWaits) return true; if (_yielding.Count == 0) { Stop(); return false; } object current = _yielding.Peek(); if (current is IEnumerator enumerator) { bool keepWaiting; try { keepWaiting = enumerator.MoveNext(); } catch { keepWaiting = true; } if (!keepWaiting) { _yielding.Pop(); if (_yielding.Count > 0) return true; Stop(); return false; } _yielding.Push(enumerator.Current); return true; } else if (current is CustomYieldInstruction yieldInstruction) { bool keepWaiting; try { keepWaiting = yieldInstruction.keepWaiting; } catch { keepWaiting = true; } if (!skipWaits) { if (!keepWaiting) _yielding.Pop(); return true; } } else if (current is WaitForSeconds waitForSeconds) { _waitUntil = EditorApplication.timeSinceStartup + (float)WaitForSecondsSecondsField.GetValue(waitForSeconds); if (!skipWaits) { _yielding.Pop(); return true; } } else if (current is WaitForSecondsRealtime waitForSecondsRealtime) { _waitUntil = EditorApplication.timeSinceStartup + waitForSecondsRealtime.waitTime; if (!skipWaits) { _yielding.Pop(); return true; } } else if (current is WaitForEndOfFrame or WaitForFixedUpdate) { if (!skipWaits) { _yielding.Pop(); return true; } } else if (current is AsyncOperation { isDone: false } asyncOperation) { if (!skipWaits) return true; InvokeCompletionEventMethod?.Invoke(asyncOperation, null); } _yielding.Pop(); if (_yielding.Count > 0) { return true; } Stop(); return false; } /// /// Continuously advances the coroutine to the next phase until it has reached the end. /// /// Note that this locks the current thread until the coroutine has fully finished. /// If the coroutine contains CustomYieldInstructions /// that take a long time to finish (or never finish in edit mode) this can cause the editor /// to freeze for the same duration. /// /// public void MoveToEnd() { while (MoveNext(true)) { } } public bool Equals(IEnumerator coroutine) { int counter = _yielding.Count; foreach (object item in _yielding) { if (counter == 1 && item == coroutine) return true; counter--; } return false; } } } ================================================ FILE: VirtueSky/Utils/Editor/EditorCoroutine.cs.meta ================================================ fileFormatVersion: 2 guid: fa886bf37579454bb7ef3eb488fc6d58 timeCreated: 1729182951 ================================================ FILE: VirtueSky/Utils/Editor/EditorGUIUtils.cs ================================================ using UnityEditor; using UnityEngine; namespace VirtueSky.UtilsEditor { #if UNITY_EDITOR public static class EditorGUIUtils { public class DisabledGUI : System.IDisposable { bool enabled; public DisabledGUI(bool disable) { enabled = GUI.enabled; GUI.enabled = !disable; } public void Dispose() { GUI.enabled = enabled; } } public class GUIColor : System.IDisposable { Color c; public GUIColor(Color c) { this.c = GUI.color; GUI.color = c; } public void Dispose() { GUI.color = c; } } public class BackgroundColor : System.IDisposable { Color c; public BackgroundColor(Color c) { this.c = GUI.color; GUI.backgroundColor = c; } public void Dispose() { GUI.backgroundColor = c; } } public class GizmosColor : System.IDisposable { Color c; public GizmosColor(Color c) { this.c = Gizmos.color; Gizmos.color = c; } public void Dispose() { Gizmos.color = c; } } public class HandlesColor : System.IDisposable { Color c; public HandlesColor(Color c) { this.c = Handles.color; Handles.color = c; } public void Dispose() { Handles.color = c; } } public class VerticalHelpBox : System.IDisposable { public VerticalHelpBox(params GUILayoutOption[] options) { EditorGUILayout.BeginVertical(EditorStyles.helpBox, options); } public void Dispose() { EditorGUILayout.EndVertical(); } } public class HorizontalHelpBox : System.IDisposable { public HorizontalHelpBox(params GUILayoutOption[] options) { EditorGUILayout.BeginHorizontal(EditorStyles.helpBox, options); } public void Dispose() { EditorGUILayout.EndHorizontal(); } } public class ScrollView : System.IDisposable { public ScrollView(ref Vector2 pos) { pos = EditorGUILayout.BeginScrollView(pos); } public void Dispose() { EditorGUILayout.EndScrollView(); } } public class HorizontalLayout : System.IDisposable { private bool centered; public HorizontalLayout(bool centered = false, params GUILayoutOption[] options) { this.centered = centered; EditorGUILayout.BeginHorizontal(options); if (centered) GUILayout.FlexibleSpace(); } public void Dispose() { if (centered) GUILayout.FlexibleSpace(); EditorGUILayout.EndHorizontal(); } } public class VerticalLayout : System.IDisposable { public VerticalLayout(params GUILayoutOption[] options) { EditorGUILayout.BeginVertical(options); } public void Dispose() { EditorGUILayout.EndVertical(); } } public class LabelWidth : System.IDisposable { float originalWidth; public LabelWidth(float width) { originalWidth = EditorGUIUtility.labelWidth; EditorGUIUtility.labelWidth = width; } public void Dispose() { EditorGUIUtility.labelWidth = originalWidth; } } public class Indent : System.IDisposable { int indent; public Indent(int indent = 1) { this.indent = indent; EditorGUI.indentLevel += indent; } public void Dispose() { EditorGUI.indentLevel -= indent; } } } #endif } ================================================ FILE: VirtueSky/Utils/Editor/EditorGUIUtils.cs.meta ================================================ fileFormatVersion: 2 guid: d009654f54214548a829eb95f493f3f6 timeCreated: 1658972649 ================================================ FILE: VirtueSky/Utils/Editor/EditorGeneric.cs ================================================ using System; using System.Collections.Generic; using Newtonsoft.Json.Serialization; using UnityEditor; using UnityEngine; using UnityEngine.UI; namespace VirtueSky.UtilsEditor { public static class EditorExtend { public static Rect GetInnerGuiPosition(SceneView sceneView) { var position = sceneView.position; position.x = position.y = 0; position.height -= EditorStyles.toolbar.fixedHeight; return position; } public static bool Get2DMouseScenePosition(out Vector2 result) { result = Vector2.zero; var cam = Camera.current; if (cam == null) return false; var guiMouse = Event.current.mousePosition; var pixelMouse = guiMouse * EditorGUIUtility.pixelsPerPoint; pixelMouse.y = cam.pixelHeight - pixelMouse.y; // không dùng Screen.height! var ray = cam.ScreenPointToRay(pixelMouse); if (ray.direction != Vector3.forward) return false; result = ray.origin; return true; } /// /// Render an object on sceneView using sprite renderers /// public static void FakeRenderSprite(GameObject obs, Vector3 position, Vector3 scale, Quaternion rotation) { var rends = obs.GetComponentsInChildren(); foreach (var rend in rends) { var bounds = rend.bounds; var pos = rend.transform.position - obs.transform.position + position; DrawSprite(rend.sprite, pos, Vector3.Scale(bounds.size, scale)); } } private static void DrawSprite(Sprite sprite, Vector3 worldSpace, Vector3 size) { if (sprite == null) return; Rect spriteTextureRect = LocalTextureRect(sprite); Handles.BeginGUI(); Vector2 v0 = HandleUtility.WorldToGUIPoint(worldSpace - size / 2f); Vector2 v1 = HandleUtility.WorldToGUIPoint(worldSpace + size / 2f); Vector2 vMin = new Vector2(Mathf.Min(v0.x, v1.x), Mathf.Min(v0.y, v1.y)); Vector2 vMax = new Vector2(Mathf.Max(v0.x, v1.x), Mathf.Max(v0.y, v1.y)); Rect r = new Rect(vMin, vMax - vMin); GUI.DrawTextureWithTexCoords(r, sprite.texture, spriteTextureRect); Handles.EndGUI(); } /// /// Calculate normalized texturerect of a sprite (0->1) /// private static Rect LocalTextureRect(Sprite sprite) { var texturePosition = sprite.textureRect.position; var textureSize = sprite.textureRect.size; texturePosition.x /= sprite.texture.width; texturePosition.y /= sprite.texture.height; textureSize.x /= sprite.texture.width; textureSize.y /= sprite.texture.height; return new Rect(texturePosition, textureSize); } public static void SkipEvent() { int id = GUIUtility.GetControlID(FocusType.Passive); GUIUtility.hotControl = id; HandleUtility.AddDefaultControl(id); Event.current.Use(); } /// /// /// /// /// /// /// /// /// /// /// /// public static bool CalculateBounds( this GameObject root, out Bounds bounds, Space space, bool renderers = true, bool colliders = true, bool meshes = false, bool graphics = true, bool particles = false) { bounds = new Bounds(); var first = true; if (space == Space.Self) { if (renderers) { var results = new List(); root.GetComponentsInChildren(results); foreach (var renderer in results) { if (!renderer.enabled) { continue; } if (!particles && renderer is ParticleSystemRenderer) { continue; } var rendererBounds = renderer.bounds; rendererBounds.SetMinMax(root.transform.InverseTransformPoint(rendererBounds.min), root.transform.InverseTransformPoint(rendererBounds.max)); if (first) { bounds = rendererBounds; first = false; } else { bounds.Encapsulate(rendererBounds); } } results = null; } if (meshes) { var meshFilters = new List(); root.GetComponentsInChildren(meshFilters); foreach (var meshFilter in meshFilters) { var mesh = Application.isPlaying ? meshFilter.mesh : meshFilter.sharedMesh; if (mesh == null) { continue; } var meshBounds = mesh.bounds; meshBounds.SetMinMax( root.transform.InverseTransformPoint(meshFilter.transform.TransformPoint(meshBounds.min)), root.transform.InverseTransformPoint(meshFilter.transform.TransformPoint(meshBounds.max))); if (first) { bounds = meshBounds; first = false; } else { bounds.Encapsulate(meshBounds); } } meshFilters = null; } if (graphics) { var results = new List(); root.GetComponentsInChildren(results); foreach (var graphic in results) { if (!graphic.enabled) { continue; } var graphicCorners = new Vector3[4] { Vector3.zero, Vector3.zero, Vector3.zero, Vector3.zero }; graphic.rectTransform.GetLocalCorners(graphicCorners); var graphicsBounds = BoundsFromCorners(graphicCorners); graphicCorners = null; if (first) { bounds = graphicsBounds; first = false; } else { bounds.Encapsulate(graphicsBounds); } } results = null; } if (colliders && first) { var results = new List(); root.GetComponentsInChildren(results); foreach (var collider in results) { if (!collider.enabled) { continue; } var colliderBounds = collider.bounds; colliderBounds.SetMinMax(root.transform.InverseTransformPoint(colliderBounds.min), root.transform.InverseTransformPoint(colliderBounds.max)); if (first) { bounds = colliderBounds; first = false; } else { bounds.Encapsulate(colliderBounds); } } results = null; } return !first; } else // if (space == Space.World) { if (renderers) { var results = new List(); root.GetComponentsInChildren(results); foreach (var renderer in results) { if (!renderer.enabled) { continue; } if (!particles && renderer is ParticleSystemRenderer) { continue; } if (first) { bounds = renderer.bounds; first = false; } else { bounds.Encapsulate(renderer.bounds); } } results = null; } if (meshes) { var filters = new List(); root.GetComponentsInChildren(filters); foreach (var meshFilter in filters) { var mesh = (Application.isPlaying ? meshFilter.mesh : meshFilter.sharedMesh); if (mesh == null) { continue; } var meshBounds = mesh.bounds; meshBounds.SetMinMax(root.transform.TransformPoint(meshBounds.min), root.transform.TransformPoint(meshBounds.max)); if (first) { bounds = meshBounds; first = false; } else { bounds.Encapsulate(meshBounds); } } filters = null; } if (graphics) { var results = new List(); root.GetComponentsInChildren(results); foreach (var graphic in results) { if (!graphic.enabled) { continue; } var graphicCorners = new Vector3[4] { Vector3.zero, Vector3.zero, Vector3.zero, Vector3.zero }; graphic.rectTransform.GetWorldCorners(graphicCorners); var graphicsBounds = BoundsFromCorners(graphicCorners); graphicCorners = null; if (first) { bounds = graphicsBounds; first = false; } else { bounds.Encapsulate(graphicsBounds); } } results = null; } if (colliders && first) { var results = new List(); root.GetComponentsInChildren(results); foreach (var collider in results) { if (!collider.enabled) { continue; } if (first) { bounds = collider.bounds; first = false; } else { bounds.Encapsulate(collider.bounds); } } results = null; } } return !first; } /// /// /// /// /// private static Bounds BoundsFromCorners(Vector3[] corners) { var minX = float.MaxValue; var minY = float.MaxValue; var minZ = float.MaxValue; var maxX = float.MinValue; var maxY = float.MinValue; var maxZ = float.MinValue; foreach (var corner in corners) { if (corner.x < minX) { minX = corner.x; } if (corner.y < minY) { minY = corner.y; } if (corner.z < minZ) { minZ = corner.z; } if (corner.x > minX) { maxX = corner.x; } if (corner.y > minY) { maxY = corner.y; } if (corner.z > minZ) { maxZ = corner.z; } } return new Bounds() { min = new Vector3(minX, minY, minZ), max = new Vector3(maxX, maxY, maxZ) }; } /// /// /// /// /// public static string ToCamelCase(this string source) { return new CamelCaseNamingStrategy().GetPropertyName(source, false); } /// /// /// /// /// public static string ToSnackCase(this string source) { return new SnakeCaseNamingStrategy().GetPropertyName(source, false); } public static bool IsSerializable(Type type) { var isSerializable = false; isSerializable |= type.IsSerializable; isSerializable |= type.Namespace == "UnityEngine"; isSerializable |= type.IsSubclassOf(typeof(MonoBehaviour)); return isSerializable; } public static void DrawSerializationError(Type type, Rect position = default) { if (position == default) { EditorGUILayout.HelpBox( $"{type} is not marked as Serializable," + "\n Add [System.Serializable] attribute.", MessageType.Error); } else { var icon = EditorGUIUtility.IconContent("Error").image; GUI.DrawTexture(position, icon, ScaleMode.ScaleToFit); } } /// /// check if given type is array or list /// /// /// public static bool IsCollectionType(this Type type) { return type.IsArray || type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>); } public static Type GetCorrectElementType(this Type type) { if (type.IsArray) { return type.GetElementType(); } if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>)) { return type.GetGenericArguments()[0]; } return null; } } } ================================================ FILE: VirtueSky/Utils/Editor/EditorGeneric.cs.meta ================================================ fileFormatVersion: 2 guid: ad38d87efa33406cac5633aa2a491d46 timeCreated: 1697172720 ================================================ FILE: VirtueSky/Utils/Editor/EditorResources.cs ================================================ using UnityEngine; namespace VirtueSky.UtilsEditor { public static class EditorResources { private const string RELATIVE_PATH = "VirtueSky/Utils/Editor/Icons"; public static Texture2D BoxContentDark => FileExtension.FindAssetWithPath("box_content_dark.psd", RELATIVE_PATH); public static Texture2D BoxBackgroundDark => FileExtension.FindAssetWithPath("box_bg_dark.psd", RELATIVE_PATH); public static Texture2D EvenBackground => FileExtension.FindAssetWithPath("even_bg.png", RELATIVE_PATH); public static Texture2D EvenBackgroundBlue => FileExtension.FindAssetWithPath("even_bg_select.png", RELATIVE_PATH); public static Texture2D EvenBackgroundDark => FileExtension.FindAssetWithPath("even_bg_dark.png", RELATIVE_PATH); public static Texture2D ScriptableFactory => FileExtension.FindAssetWithPath("scriptable_factory.png", RELATIVE_PATH); public static Texture2D IconAds => FileExtension.FindAssetWithPath("icon_ads.png", RELATIVE_PATH); public static Texture2D IconIap => FileExtension.FindAssetWithPath("icon_iap.png", RELATIVE_PATH); public static Texture2D IconLocale => FileExtension.FindAssetWithPath("icon_locale.png", RELATIVE_PATH); public static Texture2D IconScriptableEvent => FileExtension.FindAssetWithPath("scriptable_event.png", RELATIVE_PATH); public static Texture2D IconScriptableVariable => FileExtension.FindAssetWithPath("scriptable_variable.png", RELATIVE_PATH); public static Texture2D IconAudio => FileExtension.FindAssetWithPath("icon_audio.png", RELATIVE_PATH); public static Texture2D IconFirebase => FileExtension.FindAssetWithPath("icon_firebase.png", RELATIVE_PATH); public static Texture2D IconAdjust => FileExtension.FindAssetWithPath("icon_adjust.png", RELATIVE_PATH); public static Texture2D IconAppsFlyer => FileExtension.FindAssetWithPath("icon_appsflyer.png", RELATIVE_PATH); public static Texture2D IconInAppReview => FileExtension.FindAssetWithPath("icon_in_app_review.png", RELATIVE_PATH); public static Texture2D IconGameService => FileExtension.FindAssetWithPath("icon_game_service.png", RELATIVE_PATH); public static Texture2D IconFolder => FileExtension.FindAssetWithPath("icon_folder.png", RELATIVE_PATH); public static Texture2D IconHierarchy => FileExtension.FindAssetWithPath("icon_hierarchy.png", RELATIVE_PATH); public static Texture2D IconPushNotification => FileExtension.FindAssetWithPath("script_noti.png", RELATIVE_PATH); public static Texture2D IconUnity => FileExtension.FindAssetWithPath("icon_unity.png", RELATIVE_PATH); public static Texture2D IconExtension => FileExtension.FindAssetWithPath("icon_extension.png", RELATIVE_PATH); public static Texture2D IconPackage => FileExtension.FindAssetWithPath("icon_package.png", RELATIVE_PATH); public static Texture2D IconAbout => FileExtension.FindAssetWithPath("icon_about.png", RELATIVE_PATH); public static Texture2D IconVirtueSky => FileExtension.FindAssetWithPath("virtuesky_removebg.png", RELATIVE_PATH); } } ================================================ FILE: VirtueSky/Utils/Editor/EditorResources.cs.meta ================================================ fileFormatVersion: 2 guid: a3357bcdcfbe439d877bd5c4507167fa timeCreated: 1697172101 ================================================ FILE: VirtueSky/Utils/Editor/EditorScriptDefineSymbols.cs ================================================ #if UNITY_EDITOR using System.Linq; using UnityEditor; namespace VirtueSky.UtilsEditor { public class EditorScriptDefineSymbols : EditorWindow { private const string defaultMenuPath = "Sunflower/ScriptDefineSymbols/"; // #region Ads // // private const string menuPathAds = defaultMenuPath + ConstantDefineSymbols.VIRTUESKY_ADS; // // [MenuItem(menuPathAds)] // public static void AdsConfigFlag() // { // SwitchFlag(ConstantDefineSymbols.VIRTUESKY_ADS); // } // // [MenuItem(menuPathAds, true)] // public static bool IsAdsConfigFlagEnable() // { // Menu.SetChecked(menuPathAds, IsFlagEnabled(ConstantDefineSymbols.VIRTUESKY_ADS)); // return true; // } // // #endregion // // #region Applovin // // private const string menuPathApplovin = defaultMenuPath + ConstantDefineSymbols.VIRTUESKY_APPLOVIN; // // [MenuItem(menuPathApplovin)] // public static void ApplovinConfigFlag() // { // SwitchFlag(ConstantDefineSymbols.VIRTUESKY_APPLOVIN); // } // // [MenuItem(menuPathApplovin, true)] // public static bool IsApplovinConfigFlagEnable() // { // Menu.SetChecked(menuPathApplovin, IsFlagEnabled(ConstantDefineSymbols.VIRTUESKY_APPLOVIN)); // return true; // } // // #endregion // // #region Admob // // private const string menuPathAdmob = defaultMenuPath + ConstantDefineSymbols.VIRTUESKY_ADMOB; // // [MenuItem(menuPathAdmob)] // public static void AdmobConfigFlag() // { // SwitchFlag(ConstantDefineSymbols.VIRTUESKY_ADMOB); // } // // [MenuItem(menuPathAdmob, true)] // public static bool IsAdmobConfigFlagEnable() // { // Menu.SetChecked(menuPathAdmob, IsFlagEnabled(ConstantDefineSymbols.VIRTUESKY_ADMOB)); // return true; // } // // #endregion // // #region Adjust // // private const string menuPathAdjust = defaultMenuPath + ConstantDefineSymbols.VIRTUESKY_ADJUST; // // [MenuItem(menuPathAdjust)] // public static void AdjustConfigFlag() // { // SwitchFlag(ConstantDefineSymbols.VIRTUESKY_ADJUST); // } // // [MenuItem(menuPathAdjust, true)] // public static bool IsAdjustConfigFlagEnable() // { // Menu.SetChecked(menuPathAdjust, IsFlagEnabled(ConstantDefineSymbols.VIRTUESKY_ADJUST)); // return true; // } // // #endregion // // #region Firebase Analytics // // private const string menuPathAnalytic = defaultMenuPath + ConstantDefineSymbols.VIRTUESKY_FIREBASE_ANALYTIC; // // [MenuItem(menuPathAnalytic)] // public static void AnalyticConfigFlag() // { // SwitchFlag(ConstantDefineSymbols.VIRTUESKY_FIREBASE_ANALYTIC); // } // // [MenuItem(menuPathAnalytic, true)] // public static bool IsAnalyticConfigFlagEnable() // { // Menu.SetChecked(menuPathAnalytic, IsFlagEnabled(ConstantDefineSymbols.VIRTUESKY_FIREBASE_ANALYTIC)); // return true; // } // // #endregion // // #region Firebase Remote Config // // private const string menuPathRemoteConfig = // defaultMenuPath + ConstantDefineSymbols.VIRTUESKY_FIREBASE_REMOTECONFIG; // // [MenuItem(menuPathRemoteConfig)] // public static void RemoteConfigConfigFlag() // { // SwitchFlag(ConstantDefineSymbols.VIRTUESKY_FIREBASE_REMOTECONFIG); // } // // [MenuItem(menuPathRemoteConfig, true)] // public static bool IsRemoteConfigConfigFlagEnable() // { // Menu.SetChecked(menuPathRemoteConfig, IsFlagEnabled(ConstantDefineSymbols.VIRTUESKY_FIREBASE_REMOTECONFIG)); // return true; // } // // #endregion // // #region Firebase App // // private const string menuPathFirebaseApp = defaultMenuPath + ConstantDefineSymbols.VIRTUESKY_FIREBASE; // // [MenuItem(menuPathFirebaseApp)] // public static void FirebaseAppConfigFlag() // { // SwitchFlag(ConstantDefineSymbols.VIRTUESKY_FIREBASE); // } // // [MenuItem(menuPathFirebaseApp, true)] // public static bool IsFirebaseAppConfigFlagEnable() // { // Menu.SetChecked(menuPathFirebaseApp, IsFlagEnabled(ConstantDefineSymbols.VIRTUESKY_FIREBASE)); // return true; // } // // #endregion // // #region Iap // // private const string menuPathIAP = defaultMenuPath + ConstantDefineSymbols.VIRTUESKY_IAP; // // [MenuItem(menuPathIAP)] // public static void IapConfigFlag() // { // SwitchFlag(ConstantDefineSymbols.VIRTUESKY_IAP); // } // // [MenuItem(menuPathIAP, true)] // public static bool IsIapFlagEnable() // { // Menu.SetChecked(menuPathIAP, IsFlagEnabled(ConstantDefineSymbols.VIRTUESKY_IAP)); // return true; // } // // #endregion // // #region Ratting // // private const string menuPathRatting = defaultMenuPath + ConstantDefineSymbols.VIRTUESKY_RATING; // // [MenuItem(menuPathRatting)] // public static void RattingConfigFlag() // { // SwitchFlag(ConstantDefineSymbols.VIRTUESKY_RATING); // } // // [MenuItem(menuPathRatting, true)] // public static bool IsRattingConfigFlagEnable() // { // Menu.SetChecked(menuPathRatting, IsFlagEnabled(ConstantDefineSymbols.VIRTUESKY_RATING)); // return true; // } // // #endregion // // #region Notification // // private const string menuPathNotification = defaultMenuPath + ConstantDefineSymbols.VIRTUESKY_NOTIFICATION; // // [MenuItem(menuPathNotification)] // public static void NotificationConfigFlag() // { // SwitchFlag(ConstantDefineSymbols.VIRTUESKY_NOTIFICATION); // } // // [MenuItem(menuPathNotification, true)] // public static bool IsNotificationConfigFlagEnable() // { // Menu.SetChecked(menuPathNotification, IsFlagEnabled(ConstantDefineSymbols.VIRTUESKY_NOTIFICATION)); // return true; // } // // #endregion // // #region AppsFlyer // // private const string menuPathAppsFlyer = defaultMenuPath + ConstantDefineSymbols.VIRTUESKY_APPSFLYER; // // [MenuItem(menuPathAppsFlyer)] // public static void AppsFlyerConfigFlag() // { // SwitchFlag(ConstantDefineSymbols.VIRTUESKY_APPSFLYER); // } // // [MenuItem(menuPathAppsFlyer, true)] // public static bool IsAppsFlyerConfigFlagEnable() // { // Menu.SetChecked(menuPathAppsFlyer, IsFlagEnabled(ConstantDefineSymbols.VIRTUESKY_APPSFLYER)); // return true; // } // // #endregion // // #region PRIME_TWEEN_DOTWEEN_ADAPTER // // private const string menuPathPrimeTweenDotweenAdapter = // defaultMenuPath + ConstantDefineSymbols.PRIME_TWEEN_DOTWEEN_ADAPTER; // // [MenuItem(menuPathPrimeTweenDotweenAdapter)] // public static void PrimeTweenDoTweenAdapterConfigFlag() // { // SwitchFlag(ConstantDefineSymbols.PRIME_TWEEN_DOTWEEN_ADAPTER); // } // // [MenuItem(menuPathPrimeTweenDotweenAdapter, true)] // public static bool IsPrimeTweenDoTweenAdapterConfigFlagEnable() // { // Menu.SetChecked(menuPathPrimeTweenDotweenAdapter, // IsFlagEnabled(ConstantDefineSymbols.PRIME_TWEEN_DOTWEEN_ADAPTER)); // return true; // } // // #endregion // // #region GPGS // // private const string menuPathGPGS = // defaultMenuPath + ConstantDefineSymbols.VIRTUESKY_GPGS; // // [MenuItem(menuPathGPGS)] // public static void GPGSConfigFlag() // { // SwitchFlag(ConstantDefineSymbols.VIRTUESKY_GPGS); // } // // [MenuItem(menuPathGPGS, true)] // public static bool IsGPGSConfigFlagEnable() // { // Menu.SetChecked(menuPathGPGS, // IsFlagEnabled(ConstantDefineSymbols.VIRTUESKY_GPGS)); // return true; // } // // #endregion // // #region Apple Auth // // private const string menuPathAppleAuth = // defaultMenuPath + ConstantDefineSymbols.VIRTUESKY_APPLE_AUTH; // // [MenuItem(menuPathAppleAuth)] // public static void AppleAuthConfigFlag() // { // SwitchFlag(ConstantDefineSymbols.VIRTUESKY_APPLE_AUTH); // } // // [MenuItem(menuPathAppleAuth, true)] // public static bool IsAppleAuthConfigFlagEnable() // { // Menu.SetChecked(menuPathAppleAuth, // IsFlagEnabled(ConstantDefineSymbols.VIRTUESKY_APPLE_AUTH)); // return true; // } // // #endregion // // #region Skeleton // // private const string menuPathSkeleton = // defaultMenuPath + ConstantDefineSymbols.VIRTUESKY_SKELETON; // // [MenuItem(menuPathSkeleton)] // public static void SkeletonConfigFlag() // { // SwitchFlag(ConstantDefineSymbols.VIRTUESKY_SKELETON); // } // // [MenuItem(menuPathSkeleton, true)] // public static bool IsSkeletonConfigFlagEnable() // { // Menu.SetChecked(menuPathAppleAuth, // IsFlagEnabled(ConstantDefineSymbols.VIRTUESKY_SKELETON)); // return true; // } // // #endregion // // #region Animancer // // private const string menuPathAnimancer = // defaultMenuPath + ConstantDefineSymbols.VIRTUESKY_ANIMANCER; // // [MenuItem(menuPathAnimancer)] // public static void AnimancerConfigFlag() // { // SwitchFlag(ConstantDefineSymbols.VIRTUESKY_ANIMANCER); // } // // [MenuItem(menuPathAnimancer, true)] // public static bool IsAnimancerConfigFlagEnable() // { // Menu.SetChecked(menuPathAppleAuth, // IsFlagEnabled(ConstantDefineSymbols.VIRTUESKY_ANIMANCER)); // return true; // } // // #endregion #region Base Functions public static void SwitchFlag(string flag) { PlayerSettings.GetScriptingDefineSymbolsForGroup( EditorUserBuildSettings.selectedBuildTargetGroup, out var defines); var enabled = defines.Contains(flag); defines = enabled ? defines.Where(value => value != flag).ToArray() : defines.Append(flag).ToArray(); PlayerSettings.SetScriptingDefineSymbolsForGroup( EditorUserBuildSettings.selectedBuildTargetGroup, defines); } public static bool IsFlagEnabled(string flag) { PlayerSettings.GetScriptingDefineSymbolsForGroup( EditorUserBuildSettings.selectedBuildTargetGroup, out var defines); return defines.Contains(flag); } #endregion } } #endif ================================================ FILE: VirtueSky/Utils/Editor/EditorScriptDefineSymbols.cs.meta ================================================ fileFormatVersion: 2 guid: aa1b7f49165047aab9cd98879dd2af84 timeCreated: 1697165306 ================================================ FILE: VirtueSky/Utils/Editor/ExSearchWindow.cs ================================================ using System; using System.Collections.Generic; using UnityEditor.Experimental.GraphView; using UnityEngine; namespace VirtueSky.UtilsEditor { public class ExSearchWindow : ScriptableObject, ISearchWindowProvider { [Flags] public enum SortType { None = 0, Directory = 1, Alphabet = 2 } private struct Entry { public readonly GUIContent content; public readonly object data; public readonly Action onSelect; public Entry(GUIContent content, object data, Action onSelect) { this.content = content; this.data = data; this.onSelect = onSelect; } } private string title = string.Empty; private Texture2D emptyIcon; private SortType sortType = SortType.Directory | SortType.Alphabet; private List entries = new List(); /// /// Generates data to populate the search window. /// /// Contextual data initially passed the window when first created. /// Returns the list of SearchTreeEntry objects displayed in the search window. public List CreateSearchTree(SearchWindowContext context) { if (sortType != SortType.None) { entries.Sort(SortEntriesByGroup); } List treeEntries = new List() {new SearchTreeGroupEntry(new GUIContent(title), 0)}; List groups = new List(); for (int i = 0; i < entries.Count; i++) { Entry entry = entries[i]; string group = string.Empty; string[] paths = entry.content.text.Split('/'); int length = paths.Length - 1; for (int j = 0; j < length; j++) { string path = paths[j]; group += path; if (!groups.Contains(group)) { treeEntries.Add(new SearchTreeGroupEntry(new GUIContent(path), j + 1)); groups.Add(group); } group += "/"; } entry.content.text = paths[length]; SearchTreeEntry searchTreeEntry = new SearchTreeEntry(entry.content); searchTreeEntry.userData = i; searchTreeEntry.level = paths.Length; treeEntries.Add(searchTreeEntry); } return treeEntries; } /// /// Selects an entry in the search tree list. /// /// The selected entry. /// Contextual data to pass to the search window when it is first created. public bool OnSelectEntry(SearchTreeEntry searchTreeEntry, SearchWindowContext context) { Entry entry = entries[(int) searchTreeEntry.userData]; if (entry.onSelect != null) { entry.onSelect.Invoke(entry.data); return true; } return false; } /// /// Add new entry. /// /// The text and icon of the search entry. /// A user specified object for attaching application specific data to a search tree entry. /// Action with data argument, which called after entry is selected. public void AddEntry(GUIContent content, object data, Action onSelect) { entries.Add(new Entry(content, data, onSelect)); } /// /// Add new entry. /// /// The text and icon of the search entry. /// Action which called after entry is selected. public void AddEntry(GUIContent content, Action onSelect) { entries.Add(new Entry(content, null, (data) => onSelect?.Invoke())); } /// /// Add new entry. /// /// The name of the search entry. /// A user specified object for attaching application specific data to a search tree entry. /// Action with data argument, which called after entry is selected. public void AddEntry(string name, object data, Action onSelect) { AddEntry(new GUIContent(name), data, onSelect); } /// /// Add new entry. /// /// The name of the search entry. /// Action which called after entry is selected. public void AddEntry(string name, Action onSelect) { AddEntry(new GUIContent(name), null, (data) => onSelect?.Invoke()); } /// /// Add new indented entity. /// /// Name of none label. /// Action which called after entry is selected. public void AddEntityIndented(string name, Action onSelect) { GUIContent content = new GUIContent(name, GetEmptyIcon()); AddEntry(content, onSelect); } /// /// Add new indented entity. /// /// Name of none label. /// A user specified object for attaching application specific data to a search tree entry. /// Action with data argument, which called after entry is selected. public void AddEntityIndented(string name, object data, Action onSelect) { GUIContent content = new GUIContent(name, GetEmptyIcon()); AddEntry(content, data, onSelect); } /// /// Open search window. /// /// Window position in screen space. /// Requested width of the window. Set to 0.0f to use the default width. /// Requested height of the window. Set to 0.0f to use the default height. public void Open(Vector2 position, float width = 0, float height = 0) { SearchWindow.Open(new SearchWindowContext(position, width, height), this); } /// /// Open search window in mouse position. /// /// Requested width of the window. Set to 0.0f to use the default width. /// Requested height of the window. Set to 0.0f to use the default height. public void Open(float width = 0, float height = 0) { Vector2 position = GUIUtility.GUIToScreenPoint(Event.current.mousePosition); Open(position, width, height); } /// /// Open search window in button position. /// /// Rectangle of GUI button. /// Requested width of the window. Set to 0.0f to use the button width. /// Requested height of the window. Set to 0.0f to use the default height. public void Open(Rect buttonRect, float width = 0, float height = 0) { Rect screenRect = GUIUtility.GUIToScreenRect(buttonRect); Vector2 position = screenRect.position; position.x += screenRect.width / 2; position.y += screenRect.height + 15; width = Mathf.Max(0, width); width = width != 0 ? width : screenRect.width; Open(position, width != 0 ? width : screenRect.width, height); } /// /// Sort entries by paths. /// /// Left hand side entry. /// Right hand side entry. private int SortEntriesByGroup(Entry lhs, Entry rhs) { string[] lhsPaths = lhs.content.text.Split('/'); string[] rhsPaths = rhs.content.text.Split('/'); int lhsLength = lhsPaths.Length; int rhsLength = rhsPaths.Length; int minLength = Mathf.Min(lhsLength, rhsLength); for (int i = 0; i < minLength; i++) { if ((sortType & SortType.Directory) != 0) { if (minLength - 1 == i) { int compareDepth = rhsLength.CompareTo(lhsLength); if (compareDepth != 0) { return compareDepth; } } } if ((sortType & SortType.Alphabet) != 0) { int compareText = lhsPaths[i].CompareTo(rhsPaths[i]); if (compareText != 0) { return compareText; } } } return 0; } /// /// Get empty icon. /// private Texture GetEmptyIcon() { if (emptyIcon == null) { emptyIcon = new Texture2D(1, 1); emptyIcon.SetPixel(0, 0, Color.clear); emptyIcon.Apply(); } return emptyIcon; } #region [Static Methods] /// /// Create ExLib search window. /// /// Window title. /// ExSearchWindow instance. public static ExSearchWindow Create(string title) { ExSearchWindow window = CreateInstance(); window.SetTitle(title); return window; } /// /// Create ExLib search window. /// /// ExSearchWindow instance. public static ExSearchWindow Create() { const string TITLE = "Entries"; return Create(TITLE); } #endregion #region [Getter / Setter] public string GetTitle() { return title; } public void SetTitle(string value) { title = value; } public SortType GetSortType() { return sortType; } public void SetSortType(SortType value) { sortType = value; } #endregion } } ================================================ FILE: VirtueSky/Utils/Editor/ExSearchWindow.cs.meta ================================================ fileFormatVersion: 2 guid: f924140accc14c36ac089612348dea4e timeCreated: 1729158618 ================================================ FILE: VirtueSky/Utils/Editor/FileExtension.cs ================================================ using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using UnityEngine; using Object = UnityEngine.Object; #if UNITY_EDITOR using UnityEditor; #endif using Newtonsoft.Json.Linq; using Debug = UnityEngine.Debug; namespace VirtueSky.UtilsEditor { #if UNITY_EDITOR public static class FileExtension { public static List FindAll(string path) where T : Object { var results = new List(); var filter = $"t:{typeof(T).Name}"; var assetNames = AssetDatabase.FindAssets(filter, new[] { path }); foreach (string assetName in assetNames) { var assetPath = AssetDatabase.GUIDToAssetPath(assetName); var asset = AssetDatabase.LoadAssetAtPath(assetPath); if (asset == null) continue; results.Add(asset); } return results; } /// /// Find all asset with type /// /// /// public static List FindAll() where T : Object { var results = new List(); var filter = $"t:{typeof(T).Name}"; var assetNames = AssetDatabase.FindAssets(filter); foreach (string assetName in assetNames) { var assetPath = AssetDatabase.GUIDToAssetPath(assetName); var asset = AssetDatabase.LoadAssetAtPath(assetPath); if (asset == null) continue; results.Add(asset); } return results; } public static T FindAssetWithPath(string fullPath) where T : Object { string path = GetPathFileInCurrentEnvironment(fullPath); var t = AssetDatabase.LoadAssetAtPath(path, typeof(T)); if (t == null) Debug.LogError($"Couldn't load the {nameof(T)} at path :{path}"); return t as T; } public static T FindAssetWithPath(string nameAsset, string relativePath) where T : Object { string path = AssetInPackagePath(relativePath, nameAsset); var t = AssetDatabase.LoadAssetAtPath(path, typeof(T)); if (t == null) Debug.LogError($"Couldn't load the {nameof(T)} at path :{path}"); return t as T; } public static T[] FindAssetsWithPath(string nameAsset, string relativePath) where T : Object { string path = AssetInPackagePath(relativePath, nameAsset); var t = AssetDatabase.LoadAllAssetsAtPath(path).OfType().ToArray(); if (t.Length == 0) Debug.LogError($"Couldn't load the {nameof(T)} at path :{path}"); return t; } public static void ChangeAssetName(Object asset, string name) { var assetPath = AssetDatabase.GetAssetPath(asset.GetInstanceID()); AssetDatabase.RenameAsset(assetPath, name); AssetDatabase.SaveAssets(); } public static T[] FindAssetAtFolder(string[] paths) where T : Object { var list = new List(); var guids = AssetDatabase.FindAssets($"t:{typeof(T).Name}", paths); foreach (var guid in guids) { var asset = AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(guid)); if (asset) { list.Add(asset); } } return list.ToArray(); } public static T FindAssetAtResource(string path) where T : ScriptableObject { T config = Resources.Load(path); if (config != null) { return config; } return null; } public static string AssetInPackagePath(string relativePath, string nameAsset) { return GetPathFileInCurrentEnvironment($"{relativePath}/{nameAsset}"); } public static string GetPathFileInCurrentEnvironment(string fullRelativePath) { var upmPath = $"Packages/com.virtuesky.sunflower/{fullRelativePath}"; var normalPath = $"Assets/Sunflower/{fullRelativePath}"; return !File.Exists(Path.GetFullPath(upmPath)) ? normalPath : upmPath; } public static string GetPathFolderInCurrentEnvironment(string fullRelativePath) { var upmPath = $"Packages/com.virtuesky.sunflower/{fullRelativePath}"; var normalPath = $"Assets/Sunflower/{fullRelativePath}"; return Directory.Exists(upmPath) ? upmPath : normalPath; } public static string FormatJson(string json) { try { JToken parsedJson = JToken.Parse(json); return parsedJson.ToString(Newtonsoft.Json.Formatting.Indented); } catch (Exception) { return json; } } public static string ManifestPath => Application.dataPath + "/../Packages/manifest.json"; public static void OpenFolderInExplorer(string path) { if (Directory.Exists(path)) { Process.Start(path); } else { Debug.LogError("The directory does not exist: " + path); } } public static void OpenFolderInFinder(string path) { if (Directory.Exists(path)) { Process.Start("open", path); } else { Debug.LogError("The directory does not exist: " + path); } } } #endif } ================================================ FILE: VirtueSky/Utils/Editor/FileExtension.cs.meta ================================================ fileFormatVersion: 2 guid: 856ea84c538240a281b59cffc972f392 timeCreated: 1694955555 ================================================ FILE: VirtueSky/Utils/Editor/GameViewUtils.cs ================================================ using System; using System.Reflection; using UnityEditor; namespace VirtueSky.UtilsEditor { #if UNITY_EDITOR public class GameViewUtils { public const int DefaultSizeCount = 18; public static readonly Resolution[] resolutions = { new Resolution("iPhone 4", 640, 960), new Resolution("iPhone 5", 640, 1136), new Resolution("iPhone 6", 750, 1334), new Resolution("iPhone 8+", 1242, 2208), new Resolution("iPhone X", 1125, 2436), new Resolution("iPhone Xs Max", 1242, 2688), new Resolution("iPhone XR ", 828, 1792), new Resolution("HD", 1080, 1920), new Resolution("iPad Retina", 1536, 2048), new Resolution("iPad Pro 10.5", 1668, 2224), new Resolution("iPad Pro 12.9", 2048, 2732), new Resolution("iPhone 11 Pro", 1125, 2436), new Resolution("iPhone 11 Pro Max", 1242, 2688) }; static readonly object gameViewSizesInstance; static readonly MethodInfo getGroup; static GameViewUtils() { var sizesType = typeof(Editor).Assembly.GetType("UnityEditor.GameViewSizes"); var singleType = typeof(ScriptableSingleton<>).MakeGenericType(sizesType); var instanceProp = singleType.GetProperty("instance"); getGroup = sizesType.GetMethod("GetGroup"); gameViewSizesInstance = instanceProp.GetValue(null, null); } public static void AddCustomSize() { foreach (var resolution in resolutions) AddCustomSize(GameViewSizeGroupType.Android, resolution.width, resolution.height, resolution.name); } static void AddCustomSize(GameViewSizeGroupType sizeGroupType, int width, int height, string text) { var group = GetGroup(sizeGroupType); var addCustomSize = getGroup.ReturnType.GetMethod("AddCustomSize"); var gvsType = typeof(UnityEditor.Editor).Assembly.GetType("UnityEditor.GameViewSize"); var ctor = gvsType.GetConstructor(new[] { typeof(UnityEditor.Editor).Assembly.GetType("UnityEditor.GameViewSizeType"), typeof(int), typeof(int), typeof(string) }); var newSize = ctor.Invoke(new object[] { 1, width, height, text }); addCustomSize.Invoke(group, new[] { newSize }); } public static void SetSize(int index) { var gvWndType = typeof(Editor).Assembly.GetType("UnityEditor.GameView"); var gvWnd = EditorWindow.GetWindow(gvWndType); var sizeSelectionCallback = gvWndType.GetMethod("SizeSelectionCallback", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); sizeSelectionCallback.Invoke(gvWnd, new object[] { index, null }); } static object GetGroup(GameViewSizeGroupType type) { return getGroup.Invoke(gameViewSizesInstance, new object[] { (int)type }); } public static int GetViewListSize() { var group = GetGroup(GameViewSizeGroupType.Android); var getDisplayTexts = group.GetType().GetMethod("GetDisplayTexts"); return (getDisplayTexts.Invoke(group, null) as string[]).Length; } } #endif [Serializable] public class Resolution { public string name; public int height; public int width; public Resolution(string name, int width, int height) { this.name = name; this.width = width; this.height = height; } } } ================================================ FILE: VirtueSky/Utils/Editor/GameViewUtils.cs.meta ================================================ fileFormatVersion: 2 guid: 75154e8e7c6146cda787abf4cae97bd1 timeCreated: 1610554859 ================================================ FILE: VirtueSky/Utils/Editor/Icons/box_bg_dark.psd.meta ================================================ fileFormatVersion: 2 guid: a0d7d4fd6c5588e42bf710818c91767a TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 12 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 0 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Server maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/box_content_dark.psd.meta ================================================ fileFormatVersion: 2 guid: 7f8c595784dabd441b571229e95d48d0 TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 12 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 0 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Server maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/even_bg.png.meta ================================================ fileFormatVersion: 2 guid: c9c1e39bce5cc9349b0ccf76a9072a11 TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 12 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 0 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Server maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/even_bg_dark.png.meta ================================================ fileFormatVersion: 2 guid: c7e58306b400d5e49b4e8d6bdf56e7c8 TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 12 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 0 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Server maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/even_bg_select.png.meta ================================================ fileFormatVersion: 2 guid: 40593549b238df24b8a6dc7bc8b27e23 TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 12 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 0 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Server maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/icon_about.png.meta ================================================ fileFormatVersion: 2 guid: 715151f76aa224d7ca98ecfca15e6507 TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/icon_adjust.png.meta ================================================ fileFormatVersion: 2 guid: 4856817a41ca94c58b2293f27bee8195 TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/icon_ads.png.meta ================================================ fileFormatVersion: 2 guid: 25c76aa4628f244f1aaf244096d3d3f0 TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/icon_appsflyer.png.meta ================================================ fileFormatVersion: 2 guid: 927f854e1e4d440149078ed384de7fad TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 51 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 51 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/icon_audio.png.meta ================================================ fileFormatVersion: 2 guid: adf7179ddd730462c8344ae003135925 TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 53 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 53 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/icon_authentication.png.meta ================================================ fileFormatVersion: 2 guid: e6bde4f6f44782647a9e30445fb10b74 TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 52 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/icon_button.png.meta ================================================ fileFormatVersion: 2 guid: 64bffa989a83702458593189b3a27b57 TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 0 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 52 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 51 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Server maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/icon_controller.png.meta ================================================ fileFormatVersion: 2 guid: 1c63e3b6583d6b54a8de6efcd2a86725 TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 0 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 52 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 51 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Server maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/icon_csharp.png.meta ================================================ fileFormatVersion: 2 guid: f865308f7c963a749b9072d9efcd9bbf TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 0 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 52 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Server maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 51 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/icon_extension.png.meta ================================================ fileFormatVersion: 2 guid: 53c2c285c95cf478eaffc4727383342e TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 53 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 53 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/icon_firebase.png.meta ================================================ fileFormatVersion: 2 guid: 400ed70fe78e444ed8036fd7463efa70 TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/icon_folder.png.meta ================================================ fileFormatVersion: 2 guid: e4deb87810b6041068305ddb7ed40b1b TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/icon_game_service.png.meta ================================================ fileFormatVersion: 2 guid: 96553426c05ac43e783c6fccc7ebda9e TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 52 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 52 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/icon_gamemanager.png.meta ================================================ fileFormatVersion: 2 guid: 86a9dd3493f67df4497023cb0db22e35 TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 0 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 52 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 51 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Server maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/icon_generator.png.meta ================================================ fileFormatVersion: 2 guid: 6d7560f524fe8e8419031f5b3d0fe423 TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 0 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 52 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Server maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 51 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/icon_hierarchy.png.meta ================================================ fileFormatVersion: 2 guid: 422b56a3ea31444cd82f5ee33cbd31d4 TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/icon_iap.png.meta ================================================ fileFormatVersion: 2 guid: 0035776e4532b40339ab2a226c3c02b2 TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 52 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 52 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/icon_in_app_review.png.meta ================================================ fileFormatVersion: 2 guid: 920b61a4fece945abad438ca34e475e9 TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 53 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 53 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/icon_leaderboard.png.meta ================================================ fileFormatVersion: 2 guid: 83412f62fe6dc9941959257e0ad3ad3b TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 53 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 53 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/icon_locale.png.meta ================================================ fileFormatVersion: 2 guid: 6ac655bb225836f4a82eb8bcb32ebea8 TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 52 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 52 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/icon_manager.png.meta ================================================ fileFormatVersion: 2 guid: 09a0b1cab6e2173438470729b45a73f1 TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 0 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 52 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Server maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 51 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/icon_package.png.meta ================================================ fileFormatVersion: 2 guid: a3c56005701154c35aea721ecd1f579a TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/icon_scriptable.png.meta ================================================ fileFormatVersion: 2 guid: ed5ec0bb4ec55df47af0ecc2bd7be5f9 TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 12 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Server maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/icon_service.png.meta ================================================ fileFormatVersion: 2 guid: 921eb218c6594e14b841e0aaf925a9cf TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 53 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/icon_sound.png.meta ================================================ fileFormatVersion: 2 guid: cf2f10eac3dea9342b741f19e985d1df TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 0 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 52 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 51 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Server maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/icon_sound_mixer.png.meta ================================================ fileFormatVersion: 2 guid: 23fb672e22185124e935486385bd367e TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 0 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 52 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 51 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Server maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/icon_unity.png.meta ================================================ fileFormatVersion: 2 guid: 6af62e0e4e89e4e9a9b14e5f1bfbe28f TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/script_noti.png.meta ================================================ fileFormatVersion: 2 guid: 7e5f4750d7e998c40a41333bba35d8b8 TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 0 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 51 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Server maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/scriptable_adjust.png.meta ================================================ fileFormatVersion: 2 guid: 1590f55a16087b747b4764e1a11fa320 TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/scriptable_adjust2.png.meta ================================================ fileFormatVersion: 2 guid: b9157b0e91856514ba3f36deebb179cd TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/scriptable_af.png.meta ================================================ fileFormatVersion: 2 guid: 923d17c486919a945a5fef5ca1ee8e9b TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/scriptable_audio.png.meta ================================================ fileFormatVersion: 2 guid: f6fa313956d229647ad5911f1b5d081a TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 0 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Server maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/scriptable_audioclip.png.meta ================================================ fileFormatVersion: 2 guid: 3db558bebc410834889c3cdb93ca89b1 TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 0 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Server maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/scriptable_event.png.meta ================================================ fileFormatVersion: 2 guid: 5ad7786ac7818964c9714ea071b638b3 TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 0 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Server maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/scriptable_event_listener.png.meta ================================================ fileFormatVersion: 2 guid: 23cedf6c21faf0b4eb783f1fb5d4679a TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 0 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Server maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/scriptable_factory.png.meta ================================================ fileFormatVersion: 2 guid: 8c137c88e13ca774ca3189bd0f401c24 TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 0 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Server maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/scriptable_firebase.png.meta ================================================ fileFormatVersion: 2 guid: c1bc3702a7695674fbddba3cae1c2a78 TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 0 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Server maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/scriptable_iap.png.meta ================================================ fileFormatVersion: 2 guid: a7c0b6e003e41ca408cabaf952160992 TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 0 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Server maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/scriptable_notification.png.meta ================================================ fileFormatVersion: 2 guid: 6a4b74d7042712c41acccbc6d90305fd TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 0 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Server maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/scriptable_particle_system.png.meta ================================================ fileFormatVersion: 2 guid: cc343a292ab7f834eb6e7c664cc31a38 TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 4 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 4 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 4 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] customData: physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] spriteCustomMetadata: entries: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/scriptable_pool.png.meta ================================================ fileFormatVersion: 2 guid: 9a1531ff57a958c4c92ab33ca22f62ef TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 0 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Server maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/scriptable_variable.png.meta ================================================ fileFormatVersion: 2 guid: 8f06818ab5c1c06439abc547979c8edd TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 0 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Server maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/scriptable_yellow_audioclip.png.meta ================================================ fileFormatVersion: 2 guid: 2579f1f676b7f2843a4cafaf429f9474 TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/scriptable_yellow_font.png.meta ================================================ fileFormatVersion: 2 guid: 6612c7be3408486478603096058345a2 TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/scriptable_yellow_fontasset.png.meta ================================================ fileFormatVersion: 2 guid: 120a98534767efd4ba0b7a9e91cda393 TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/scriptable_yellow_gameobject.png.meta ================================================ fileFormatVersion: 2 guid: bfd31c3e578dee04295c2133a97be5dd TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/scriptable_yellow_material.png.meta ================================================ fileFormatVersion: 2 guid: 0bf47bf639988dc499e672dd3d0b7c26 TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/scriptable_yellow_sprite.png.meta ================================================ fileFormatVersion: 2 guid: b2b3b70f4d3c0884faa424282862c6ca TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/scriptable_yellow_text.png.meta ================================================ fileFormatVersion: 2 guid: 13605300fcfb1fd45b49212af32ba2f8 TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/scriptable_yellow_textasset.png.meta ================================================ fileFormatVersion: 2 guid: 5b605beec23f2f6408ce4cae4dedd075 TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/scriptable_yellow_texture.png.meta ================================================ fileFormatVersion: 2 guid: a7f0847a6f95e2e46a76f375e4c2d001 TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/scriptable_yellow_videoclip.png.meta ================================================ fileFormatVersion: 2 guid: a3d36db6a75640543bcec2d532f8498d TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons/virtuesky_removebg.png.meta ================================================ fileFormatVersion: 2 guid: 7a9683410876c4651adc20351e3e2c8d TextureImporter: internalIDToNameTable: [] externalObjects: {} serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 0 sRGBTexture: 1 linearTexture: 0 fadeOut: 0 borderMipMap: 0 mipMapsPreserveCoverage: 0 alphaTestReferenceValue: 0.5 mipMapFadeDistanceStart: 1 mipMapFadeDistanceEnd: 3 bumpmap: convertToNormalMap: 0 externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 seamlessCubemap: 0 textureFormat: 1 maxTextureSize: 2048 textureSettings: serializedVersion: 2 filterMode: 1 aniso: 1 mipBias: 0 wrapU: 1 wrapV: 1 wrapW: 0 nPOTScale: 0 lightmap: 0 compressionQuality: 50 spriteMode: 0 spriteExtrude: 1 spriteMeshType: 1 alignment: 0 spritePivot: {x: 0.5, y: 0.5} spritePixelsToUnits: 100 spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 2 textureShape: 1 singleChannelComponent: 0 flipbookRows: 1 flipbookColumns: 1 maxTextureSizeSet: 0 compressionQualitySet: 0 textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 swizzle: 50462976 cookieLightType: 0 platformSettings: - serializedVersion: 3 buildTarget: DefaultTexturePlatform maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Standalone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: iPhone maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 51 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 - serializedVersion: 3 buildTarget: Android maxTextureSize: 2048 resizeAlgorithm: 0 textureFormat: 50 textureCompression: 1 compressionQuality: 50 crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 1 ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] physicsShape: [] bones: [] spriteID: internalID: 0 vertices: [] indices: edges: [] weights: [] secondaryTextures: [] nameFileIdTable: {} mipmapLimitGroupName: pSDRemoveMatte: 0 userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Icons.meta ================================================ fileFormatVersion: 2 guid: 9c1e9c5bf1a843c18bf32a98f6910ca3 timeCreated: 1697170213 ================================================ FILE: VirtueSky/Utils/Editor/RegistryManager.cs ================================================ using System.Collections.Generic; using System.IO; using Newtonsoft.Json.Linq; using UnityEditor.PackageManager; using UnityEngine; using VirtueSky.SimpleJSON; namespace VirtueSky.UtilsEditor { public static class RegistryManager { private static readonly string ManifestPath = Path.Combine(Application.dataPath, "..", "Packages", "manifest.json"); public static void Add(string name, string version) { var json = JObject.Parse(File.ReadAllText(ManifestPath)); var dependencies = (JObject)json["dependencies"]; if (dependencies != null) { foreach (var dependency in dependencies) { if (dependency.Key.Equals(name)) return; } dependencies.Add(name, version); } Write(json); } public static void AddOverrideVersion(string name, string version) { (bool isInstall, string currentVersion) = IsInstalled(name); if (currentVersion == "") { Add(name, version); Resolve(); } else { if (version.Equals(currentVersion)) { Debug.Log($"This version of {name} is installed"); } else { Remove(name); Add(name, version); Resolve(); } } } public static void Remove(string name) { var json = JObject.Parse(File.ReadAllText(ManifestPath)); var dependencies = (JObject)json["dependencies"]; dependencies?.Remove(name); Write(json); } public static (bool, string) IsInstalled(string name) { var json = JObject.Parse(File.ReadAllText(ManifestPath)); var dependencies = (JObject)json["dependencies"]; if (dependencies != null) { foreach (var dependency in dependencies) { if (dependency.Key.Equals(name)) return (true, dependency.Value.ToString()); } } return (false, ""); } public static bool IsInstalledPackage(string name) { var json = JObject.Parse(File.ReadAllText(ManifestPath)); var dependencies = (JObject)json["dependencies"]; if (dependencies != null) { foreach (var dependency in dependencies) { if (dependency.Key.Equals(name)) return true; } } return false; } public static void Resolve() { Client.Resolve(); } private static void Write(JObject json) { File.WriteAllText(ManifestPath, json.ToString()); } public static (string, string) GetPackageInManifestByPackageName(string packageName) { string manifestContent = GetManifestContent(); if (manifestContent == null) { Debug.LogError("Could not find fileManifest.json"); return (null, null); } JSONNode manifestJson = JSON.Parse(manifestContent); JSONNode dependencies = manifestJson["dependencies"]; if (dependencies != null && dependencies.Count > 0) { // List libraries = new List(); foreach (KeyValuePair dep in dependencies.AsObject) { if (packageName == $"\"{dep.Key}\"") { // packageName and packageVersion return ($"\"{dep.Key}\"", $": {dep.Value}"); } // libraries.Add($"\"{dep.Key}\": {dep.Value}"); } } else { Debug.LogError("Could not find dependencies or dependencies null."); return (null, null); } return (null, null); } public static void AddPackageInManifest(string packageFullName) { string manifestContent = GetManifestContent(); if (manifestContent != null) { int dependenciesIndex = manifestContent.IndexOf("\"dependencies\": {") + "\"dependencies\": {".Length; manifestContent = manifestContent.Insert(dependenciesIndex, packageFullName); WriteAllManifestContent(manifestContent); Debug.Log($"Add {packageFullName} to manifest"); } } public static void RemovePackageInManifest(string packageFullName) { string manifestContent = GetManifestContent(); if (manifestContent != null) { // int dependenciesIndex = manifestContent.IndexOf("\"dependencies\": {") + // "\"dependencies\": {".Length; manifestContent = manifestContent.Replace(packageFullName, ""); WriteAllManifestContent(manifestContent); Debug.Log($"Remove {packageFullName} to manifest"); } } public static string GetManifestContent() { if (File.Exists(ManifestPath)) { return File.ReadAllText(ManifestPath); } return null; } public static void WriteAllManifestContent(string manifestContent) { File.WriteAllText(ManifestPath, FileExtension.FormatJson(manifestContent)); } } } ================================================ FILE: VirtueSky/Utils/Editor/RegistryManager.cs.meta ================================================ fileFormatVersion: 2 guid: c3b8339c355d4086a8413fc879e4b2cf timeCreated: 1697173240 ================================================ FILE: VirtueSky/Utils/Editor/TemplateAssembly/PurchasingGeneratedAsmdef.txt ================================================ { "name": "virtuesky.purchasing.generate", "rootNamespace": "", "references": [ "GUID:94e1de2458b07d0bf1e9f13e6ae06443", "GUID:d0bf1e9f644394e1de13e6ae02458b07" ], "includePlatforms": [], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], "versionDefines": [], "noEngineReferences": false } ================================================ FILE: VirtueSky/Utils/Editor/TemplateAssembly/PurchasingGeneratedAsmdef.txt.meta ================================================ fileFormatVersion: 2 guid: 46b89d27511c4a579d5b1a1ebe589cf9 timeCreated: 1697512999 ================================================ FILE: VirtueSky/Utils/Editor/TemplateAssembly/PurchasingGeneratedAsmdefMeta.txt ================================================ fileFormatVersion: 2 guid: a90b00dc83a89964cb7641c304492d29 AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/TemplateAssembly/PurchasingGeneratedAsmdefMeta.txt.meta ================================================ fileFormatVersion: 2 guid: d9fc3d0a2c214d6b915bc32a042a9ab6 timeCreated: 1697513148 ================================================ FILE: VirtueSky/Utils/Editor/TemplateAssembly.meta ================================================ fileFormatVersion: 2 guid: 1d7799227ee44deba408233b2ddbe863 timeCreated: 1697512232 ================================================ FILE: VirtueSky/Utils/Editor/TextureUtils.cs ================================================ #if UNITY_EDITOR #endif using System; using System.IO; using UnityEditor; using UnityEngine; using Object = UnityEngine.Object; namespace VirtueSky.UtilsEditor { #if UNITY_EDITOR public static class TextureUtils { public static void CaptureToFile(Camera cam, string path, int width = 1024, int height = 1024, int depth = 24, RenderTextureFormat format = RenderTextureFormat.ARGB32, TextureExtension extension = TextureExtension.PNG, bool refresh = true) { var rt = new RenderTexture(width, height, depth, format); cam.targetTexture = rt; cam.Render(); RenderTextureToFile(rt, path, extension, refresh); cam.targetTexture = null; Object.Destroy(rt); } public static void RenderTextureToFile(RenderTexture rt, string path, TextureExtension extension = TextureExtension.PNG, bool refresh = true) { var oldRt = RenderTexture.active; var tex = new Texture2D(rt.width, rt.height); RenderTexture.active = rt; tex.ReadPixels(new Rect(0, 0, rt.width, rt.height), 0, 0); tex.Apply(); Texture2DToFile(tex, path, extension); RenderTexture.active = oldRt; } public static void Texture2DToFile(Texture2D tex, string path, TextureExtension extension = TextureExtension.PNG, bool refresh = true) { switch (extension) { case TextureExtension.PNG: File.WriteAllBytes(path + ".png", tex.EncodeToPNG()); break; case TextureExtension.JPG: File.WriteAllBytes(path + ".jpg", tex.EncodeToJPG()); break; default: throw new ArgumentOutOfRangeException(nameof(extension), extension, null); } if (refresh) { AssetDatabase.Refresh(); } } public enum TextureExtension { PNG, JPG } } #endif } ================================================ FILE: VirtueSky/Utils/Editor/TextureUtils.cs.meta ================================================ fileFormatVersion: 2 guid: 03a0e739fe864fc69e58652dc60f8e67 timeCreated: 1608451762 ================================================ FILE: VirtueSky/Utils/Editor/Uniform.cs ================================================ using System.Collections.Generic; using System.Linq; using UnityEditor; using UnityEngine; namespace VirtueSky.UtilsEditor { public struct Uniform { #region field private static GUIStyle contentList; private static GUIStyle contentListBlue; private static GUIStyle contentListDark; private static GUIStyle contentBox; private static GUIStyle box; private static GUIStyle foldoutButton; private static GUIStyle foldoutIcon; private static GUIStyle installedIcon; private static GUIStyle headerLabel; private static readonly Dictionary CachedIconContent = new Dictionary(); private static readonly UniformFoldoutState FoldoutSettings = new UniformFoldoutState(); #endregion #region prop public static GUIStyle ContentList { get { if (contentList != null) return contentList; contentList = new GUIStyle { border = new RectOffset(2, 2, 2, 2), normal = { background = EditorResources.EvenBackground } }; return contentList; } } public static GUIStyle ContentListBlue { get { if (contentListBlue != null) return contentListBlue; contentListBlue = new GUIStyle { border = new RectOffset(2, 2, 2, 2), normal = { background = EditorResources.EvenBackgroundBlue } }; return contentListBlue; } } public static GUIStyle ContentListDark { get { if (contentListDark != null) return contentListDark; contentListDark = new GUIStyle { border = new RectOffset(2, 2, 2, 2), normal = { background = EditorResources.EvenBackgroundDark } }; return contentListDark; } } public static GUIStyle BoxContent { get { if (contentBox != null) return contentBox; contentBox = new GUIStyle { border = new RectOffset(2, 2, 2, 2), normal = { background = EditorResources.BoxContentDark, scaledBackgrounds = new[] { EditorResources.BoxContentDark } } }; return contentBox; } } public static GUIStyle Box { get { if (box != null) return box; box = new GUIStyle { border = new RectOffset(2, 2, 2, 2), margin = new RectOffset(2, 2, 2, 2), normal = { background = EditorResources.BoxBackgroundDark, scaledBackgrounds = new[] { EditorResources.BoxBackgroundDark } } }; return box; } } public static GUIStyle FoldoutButton { get { if (foldoutButton != null) return foldoutButton; foldoutButton = new GUIStyle { normal = new GUIStyleState { textColor = Color.white }, margin = new RectOffset(4, 4, 4, 4), padding = new RectOffset(0, 0, 2, 3), stretchWidth = true, richText = true, fontSize = 12, fontStyle = FontStyle.Bold }; return foldoutButton; } } public static GUIStyle FoldoutIcon { get { if (foldoutIcon != null) return foldoutIcon; foldoutIcon = new GUIStyle { padding = new RectOffset(0, 0, 5, 0) }; return foldoutIcon; } } public static GUIStyle InstalledIcon { get { if (installedIcon != null) return installedIcon; installedIcon = new GUIStyle { padding = new RectOffset(0, 0, 3, 0), fixedWidth = 30, fixedHeight = 30 }; return installedIcon; } } public static GUIStyle HeaderLabel { get { if (headerLabel != null) return headerLabel; headerLabel = new GUIStyle(EditorStyles.label) { fontSize = 13, fontStyle = FontStyle.Bold }; return headerLabel; } } #endregion #region color public static readonly Color Green = new(0.31f, 0.98f, 0.48f, 0.66f); public static readonly Color Orange = new(1f, 0.72f, 0.42f, 0.66f); public static readonly Color Blue = new(0f, 1f, 0.97f, 0.27f); public static readonly Color Purple = new(0.74f, 0.58f, 0.98f, 0.39f); public static readonly Color Red = new(1f, 0.16f, 0.16f, 0.66f); public static readonly Color Pink = new(1f, 0.47f, 0.78f, 0.66f); public static readonly Color RichBlack = new(0.04f, 0.05f, 0.11f); public static readonly Color FieryRose = new(0.97f, 0.33f, 0.41f); public static readonly Color DeepCarminePink = new(1f, 0.2f, 0.2f); public static readonly Color FluorescentBlue = new(0.2f, 1f, 1f); #endregion #region draw public static void DrawBox(Rect position, GUIStyle style, bool isHover = false, bool isActive = false, bool on = false, bool hasKeyboardFocus = false) { if (Event.current.type == EventType.Repaint) { style.Draw(position, GUIContent.none, isHover, isActive, on, hasKeyboardFocus); } } /// /// Icon content /// /// /// /// public static GUIContent IconContent(string name, string tooltip = "") { if (CachedIconContent.TryGetValue(name, out var result)) return result ?? GUIContent.none; var builtinIcon = EditorGUIUtility.IconContent(name) ?? new GUIContent(Texture2D.whiteTexture); result = new GUIContent(builtinIcon.image, tooltip); CachedIconContent.Add(name, result); return result; } /// /// Draw header with title /// /// public static void DrawHeader(string title) { var bgStyle = new GUIStyle(GUIStyle.none) { normal = { background = CreateTexture(RichBlack) } }; GUILayout.BeginVertical(bgStyle, GUILayout.Height(60)); GUILayout.BeginHorizontal(); var iconStyle = new GUIStyle(GUIStyle.none) { padding = new RectOffset(2, 0, 2, 2) }; // GUILayout.Box(EditorResources.Dreamblale, iconStyle, GUILayout.Width(60), GUILayout.Height(60)); var titleStyle = new GUIStyle(GUIStyle.none) { margin = new RectOffset(4, 4, 4, 4), fontSize = 20, fontStyle = FontStyle.Bold, alignment = TextAnchor.MiddleLeft, wordWrap = false, richText = true, imagePosition = ImagePosition.ImageLeft, fixedHeight = 50, stretchHeight = true, stretchWidth = true, normal = { textColor = Color.white } }; EditorGUILayout.LabelField(title, titleStyle); GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); GUILayout.EndVertical(); } // public static Texture2D Dreamblale => ProjectDatabase.FindAssetWithPath("dreamblade.png", RELATIVE_PATH); public static Texture2D CreateTexture(Color color) { var result = new Texture2D(1, 1, TextureFormat.RGBA32, false); result.SetPixel(0, 0, color); result.Apply(); return result; } /// /// Draw only the property specified. /// /// /// /// public static void DrawOnlyField(SerializedObject serializedObject, string fieldName, bool isReadOnly) { serializedObject.Update(); var prop = serializedObject.GetIterator(); if (prop.NextVisible(true)) { do { if (prop.name != fieldName) continue; GUI.enabled = !isReadOnly; EditorGUILayout.PropertyField(serializedObject.FindProperty(prop.name), true); GUI.enabled = true; } while (prop.NextVisible(false)); } serializedObject.ApplyModifiedProperties(); } /// /// Draws a line in the inspector. /// /// public static void DrawLine(int height = 1) { var rect = EditorGUILayout.GetControlRect(false, height); rect.height = height; EditorGUI.DrawRect(rect, new Color(0.5f, 0.5f, 0.5f, 1)); } /// /// Draw a selectable object /// /// /// public static void DrawSelectableObject(Object obj, string[] labels) { GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (GUILayout.Button(labels[0], GUILayout.MaxWidth(300))) EditorGUIUtility.PingObject(obj); if (GUILayout.Button(labels[1], GUILayout.MaxWidth(75))) { EditorWindow.FocusWindowIfItsOpen(typeof(SceneView)); Selection.activeObject = obj; SceneView.FrameLastActiveSceneView(); } GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); GUILayout.Space(2); } /// /// Draws all properties like base.OnInspectorGUI() but excludes a field by name. /// /// /// The name of the field that should be excluded. Example: "m_Script" will skip the default Script field. public static void DrawInspectorExcept(SerializedObject serializedObject, string fieldToSkip) { Uniform.DrawInspectorExcept(serializedObject, new[] { fieldToSkip }); } /// /// Draws all properties like base.OnInspectorGUI() but excludes the specified fields by name. /// /// /// /// An array of names that should be excluded. /// Example: new string[] { "m_Script" , "myInt" } will skip the default Script field and the Integer field myInt. /// public static void DrawInspectorExcept(SerializedObject serializedObject, string[] fieldsToSkip) { serializedObject.Update(); var prop = serializedObject.GetIterator(); if (prop.NextVisible(true)) { do { if (fieldsToSkip.Any(prop.name.Contains)) continue; EditorGUILayout.PropertyField(serializedObject.FindProperty(prop.name), true); } while (prop.NextVisible(false)); } serializedObject.ApplyModifiedProperties(); } /// /// Draw group selection with header /// /// /// /// /// /// public static float DrawGroupFoldout(string key, string sectionName, System.Action drawer, bool defaultFoldout = true, bool isShowContent = true) { bool foldout = GetFoldoutState(key, defaultFoldout); var rect = EditorGUILayout.BeginVertical(Box, GUILayout.MinHeight(foldout && isShowContent ? 30 : 0)); if (!isShowContent) { EditorGUILayout.LabelField(sectionName); } else { EditorGUILayout.BeginHorizontal(); // Header label (and button). if (GUILayout.Button($" {sectionName}", FoldoutButton)) SetFoldoutState(key, !foldout); // The expand/collapse icon. var buttonRect = GUILayoutUtility.GetLastRect(); var iconRect = new Rect(buttonRect.x, buttonRect.y, 10, buttonRect.height); GUI.Label(iconRect, foldout ? IconContent("d_IN_foldout_act_on") : IconContent("d_IN_foldout"), FoldoutIcon); EditorGUILayout.EndHorizontal(); // Draw the section content. if (foldout) GUILayout.Space(5); if (foldout && drawer != null) drawer(); } float height = rect.height; EditorGUILayout.EndVertical(); height += 4; return height; } /// /// Draw group selection with header /// /// /// /// /// /// /// public static float DrawGroupFoldoutWithRightClick( string key, string sectionName, System.Action drawer, System.Action actionRightClick, bool defaultFoldout = true, bool isShowContent = true) { bool foldout = GetFoldoutState(key, defaultFoldout); var rect = EditorGUILayout.BeginVertical(Box, GUILayout.MinHeight(foldout && isShowContent ? 30 : 0)); if (!isShowContent) { EditorGUILayout.LabelField(sectionName); } else { EditorGUILayout.BeginHorizontal(); // Header label (and button). if (GUILayout.Button($" {sectionName}", FoldoutButton)) { if (Event.current.button == 1) { actionRightClick?.Invoke(); return rect.height; } SetFoldoutState(key, !foldout); } // The expand/collapse icon. var buttonRect = GUILayoutUtility.GetLastRect(); var iconRect = new Rect(buttonRect.x, buttonRect.y, 10, buttonRect.height); GUI.Label(iconRect, foldout ? IconContent("d_IN_foldout_act_on") : IconContent("d_IN_foldout"), FoldoutIcon); EditorGUILayout.EndHorizontal(); // Draw the section content. if (foldout) GUILayout.Space(5); if (foldout && drawer != null) drawer(); } float height = rect.height; EditorGUILayout.EndVertical(); height += 4; return height; } /// /// /// /// /// /// /// /// public static string DrawTextField(string fieldTitle, string text, GUILayoutOption labelWidth, GUILayoutOption textFieldWidthOption = null) { GUILayout.BeginHorizontal(); GUILayout.Space(4); EditorGUILayout.LabelField(new GUIContent(fieldTitle), labelWidth); GUILayout.Space(4); text = textFieldWidthOption == null ? GUILayout.TextField(text) : GUILayout.TextField(text, textFieldWidthOption); GUILayout.Space(4); GUILayout.EndHorizontal(); GUILayout.Space(4); return text; } /// /// Centers a rect inside another window. /// /// /// /// public static Rect CenterInWindow(Rect window, Rect origin) { var pos = window; float w = (origin.width - pos.width) * 0.5f; float h = (origin.height - pos.height) * 0.5f; pos.x = origin.x + w; pos.y = origin.y + h; return pos; } /// /// Draw label installed and icon /// public static void DrawInstalled(string version) { EditorGUILayout.BeginHorizontal(); var label = $"Installed {version}"; GUILayout.Label(label); var lastRect = GUILayoutUtility.GetLastRect(); var iconRect = new Rect(lastRect.x + label.Length * 6f, lastRect.y, 10, lastRect.height); GUI.Label(iconRect, Uniform.IconContent("CollabNew"), InstalledIcon); EditorGUILayout.EndHorizontal(); } #endregion #region foldout state public static bool GetFoldoutState(string key, bool defaultFoldout = true) { if (!FoldoutSettings.ContainsKey(key)) FoldoutSettings.Add(key, defaultFoldout); return FoldoutSettings[key]; } public static void SetFoldoutState(string key, bool state) { if (!FoldoutSettings.ContainsKey(key)) { FoldoutSettings.Add(key, state); } else { FoldoutSettings[key] = state; } } [System.Serializable] public class FoldoutState { public string key; public bool state; } [System.Serializable] public class UniformFoldoutState { public List uniformFoldouts; public UniformFoldoutState() { uniformFoldouts = new List(); } public bool ContainsKey(string key) { return uniformFoldouts.Any(foldoutState => foldoutState.key.Equals(key)); } public void Add(string key, bool value) { uniformFoldouts.Add(new FoldoutState { key = key, state = value }); } public bool this[string key] { get { foreach (var foldoutState in uniformFoldouts) { if (foldoutState.key.Equals(key)) { return foldoutState.state; } } return false; } set { foreach (var foldoutState in uniformFoldouts) { if (foldoutState.key.Equals(key)) { foldoutState.state = value; break; } } } } } #endregion } } ================================================ FILE: VirtueSky/Utils/Editor/Uniform.cs.meta ================================================ fileFormatVersion: 2 guid: 9f0e29e6ef9d4f7fa00db23754c9ee67 timeCreated: 1697168886 ================================================ FILE: VirtueSky/Utils/Editor/UnityPackage/Note_Package.txt ================================================ - Version Max Sdk: 8.6.2 - Version Google Game Play Service: v2.1.0 ================================================ FILE: VirtueSky/Utils/Editor/UnityPackage/Note_Package.txt.meta ================================================ fileFormatVersion: 2 guid: 0acfd990870be8348a3ea75a1ef44ffa TextScriptImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/UnityPackage/google-play-game.unitypackage.meta ================================================ fileFormatVersion: 2 guid: 2008ec393deb9b14697035729927bc9c DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/UnityPackage/max-sdk.unitypackage.meta ================================================ fileFormatVersion: 2 guid: 53509e528178d1d4891a421c469c5c6e DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/UnityPackage.meta ================================================ fileFormatVersion: 2 guid: 7f0ec4ddaa968214bb0e3a8413730912 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor/Virtuesky.Sunflower.UtilsEdtitor.asmdef ================================================ { "name": "Virtuesky.Sunflower.UtilsEdtitor", "rootNamespace": "", "references": [ "GUID:98c7400721ddc874d9bad4ee2f3f66d6", "GUID:efdee36e63e4ce34a91071531ec746c1" ], "includePlatforms": [ "Editor" ], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], "versionDefines": [], "noEngineReferences": false } ================================================ FILE: VirtueSky/Utils/Editor/Virtuesky.Sunflower.UtilsEdtitor.asmdef.meta ================================================ fileFormatVersion: 2 guid: c904f6d969e991d459a0843b71c22ec5 AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Editor.meta ================================================ fileFormatVersion: 2 guid: 3deb402fc5e746f8a228f15e52329ed1 timeCreated: 1699932105 ================================================ FILE: VirtueSky/Utils/Runtime/ColorExtensions.cs ================================================ using UnityEngine; namespace VirtueSky.Utils { public static class ColorExtensions { // Convert the TitleColor enum to an actual Color32 public static Color32 ToColor(this CustomColor color) { switch (color) { case CustomColor.AliceBlue: return new Color32(240, 248, 255, 255); case CustomColor.AntiqueWhite: return new Color32(250, 235, 215, 255); case CustomColor.Aqua: return new Color32(0, 255, 255, 255); case CustomColor.Aquamarine: return new Color32(127, 255, 212, 255); case CustomColor.Azure: return new Color32(240, 255, 255, 255); case CustomColor.Beige: return new Color32(245, 245, 220, 255); case CustomColor.Bisque: return new Color32(255, 228, 196, 255); case CustomColor.Black: return new Color32(0, 0, 0, 255); case CustomColor.BlanchedAlmond: return new Color32(255, 235, 205, 255); case CustomColor.Blue: return new Color32(0, 0, 255, 255); case CustomColor.BlueViolet: return new Color32(138, 43, 226, 255); case CustomColor.Brown: return new Color32(165, 42, 42, 255); case CustomColor.Burlywood: return new Color32(222, 184, 135, 255); case CustomColor.CadetBlue: return new Color32(95, 158, 160, 255); case CustomColor.Chartreuse: return new Color32(127, 255, 0, 255); case CustomColor.Chocolate: return new Color32(210, 105, 30, 255); case CustomColor.Coral: return new Color32(255, 127, 80, 255); case CustomColor.CornflowerBlue: return new Color32(100, 149, 237, 255); case CustomColor.Cornsilk: return new Color32(255, 248, 220, 255); case CustomColor.Crimson: return new Color32(220, 20, 60, 255); case CustomColor.Cyan: return new Color32(0, 255, 255, 255); case CustomColor.DarkBlue: return new Color32(0, 0, 139, 255); case CustomColor.DarkCyan: return new Color32(0, 139, 139, 255); case CustomColor.DarkGoldenrod: return new Color32(184, 134, 11, 255); case CustomColor.DarkGray: return new Color32(169, 169, 169, 255); case CustomColor.DarkGreen: return new Color32(0, 100, 0, 255); case CustomColor.DarkKhaki: return new Color32(189, 183, 107, 255); case CustomColor.DarkMagenta: return new Color32(139, 0, 139, 255); case CustomColor.DarkOliveGreen: return new Color32(85, 107, 47, 255); case CustomColor.DarkOrange: return new Color32(255, 140, 0, 255); case CustomColor.DarkOrchid: return new Color32(153, 50, 204, 255); case CustomColor.DarkRed: return new Color32(139, 0, 0, 255); case CustomColor.DarkSalmon: return new Color32(233, 150, 122, 255); case CustomColor.DarkSeaGreen: return new Color32(143, 188, 143, 255); case CustomColor.DarkSlateBlue: return new Color32(72, 61, 139, 255); case CustomColor.DarkSlateGray: return new Color32(47, 79, 79, 255); case CustomColor.DarkTurquoise: return new Color32(0, 206, 209, 255); case CustomColor.DarkViolet: return new Color32(148, 0, 211, 255); case CustomColor.DeepPink: return new Color32(255, 20, 147, 255); case CustomColor.DeepSkyBlue: return new Color32(0, 191, 255, 255); case CustomColor.DimGray: return new Color32(105, 105, 105, 255); case CustomColor.DodgerBlue: return new Color32(30, 144, 255, 255); case CustomColor.FireBrick: return new Color32(178, 34, 34, 255); case CustomColor.FloralWhite: return new Color32(255, 250, 240, 255); case CustomColor.ForestGreen: return new Color32(34, 139, 34, 255); case CustomColor.Fuchsia: return new Color32(255, 0, 255, 255); case CustomColor.Gainsboro: return new Color32(220, 220, 220, 255); case CustomColor.GhostWhite: return new Color32(248, 248, 255, 255); case CustomColor.Gold: return new Color32(255, 215, 0, 255); case CustomColor.Goldenrod: return new Color32(218, 165, 32, 255); case CustomColor.Gray: return new Color32(128, 128, 128, 255); case CustomColor.Green: return new Color32(0, 128, 0, 255); case CustomColor.GreenYellow: return new Color32(173, 255, 47, 255); case CustomColor.Honeydew: return new Color32(240, 255, 240, 255); case CustomColor.HotPink: return new Color32(255, 105, 180, 255); case CustomColor.IndianRed: return new Color32(205, 92, 92, 255); case CustomColor.Indigo: return new Color32(75, 0, 130, 255); case CustomColor.Ivory: return new Color32(255, 255, 240, 255); case CustomColor.Khaki: return new Color32(240, 230, 140, 255); case CustomColor.Lavender: return new Color32(230, 230, 250, 255); case CustomColor.Lavenderblush: return new Color32(255, 240, 245, 255); case CustomColor.LawnGreen: return new Color32(124, 252, 0, 255); case CustomColor.LemonChiffon: return new Color32(255, 250, 205, 255); case CustomColor.LightBlue: return new Color32(173, 216, 230, 255); case CustomColor.LightCoral: return new Color32(240, 128, 128, 255); case CustomColor.LightCyan: return new Color32(224, 255, 255, 255); case CustomColor.LightGoldenodYellow: return new Color32(250, 250, 210, 255); case CustomColor.LightGray: return new Color32(211, 211, 211, 255); case CustomColor.LightGreen: return new Color32(144, 238, 144, 255); case CustomColor.LightPink: return new Color32(255, 182, 193, 255); case CustomColor.LightSalmon: return new Color32(255, 160, 122, 255); case CustomColor.LightSeaGreen: return new Color32(32, 178, 170, 255); case CustomColor.LightSkyBlue: return new Color32(135, 206, 250, 255); case CustomColor.LightSlateGray: return new Color32(119, 136, 153, 255); case CustomColor.LightSteelBlue: return new Color32(176, 196, 222, 255); case CustomColor.LightYellow: return new Color32(255, 255, 224, 255); case CustomColor.Lime: return new Color32(0, 255, 0, 255); case CustomColor.LimeGreen: return new Color32(50, 205, 50, 255); case CustomColor.Linen: return new Color32(250, 240, 230, 255); case CustomColor.Magenta: return new Color32(255, 0, 255, 255); case CustomColor.Maroon: return new Color32(128, 0, 0, 255); case CustomColor.MediumAquamarine: return new Color32(102, 205, 170, 255); case CustomColor.MediumBlue: return new Color32(0, 0, 205, 255); case CustomColor.MediumOrchid: return new Color32(186, 85, 211, 255); case CustomColor.MediumPurple: return new Color32(147, 112, 219, 255); case CustomColor.MediumSeaGreen: return new Color32(60, 179, 113, 255); case CustomColor.MediumSlateBlue: return new Color32(123, 104, 238, 255); case CustomColor.MediumSpringGreen: return new Color32(0, 250, 154, 255); case CustomColor.MediumTurquoise: return new Color32(72, 209, 204, 255); case CustomColor.MediumVioletRed: return new Color32(199, 21, 133, 255); case CustomColor.MidnightBlue: return new Color32(25, 25, 112, 255); case CustomColor.Mintcream: return new Color32(245, 255, 250, 255); case CustomColor.MistyRose: return new Color32(255, 228, 225, 255); case CustomColor.Moccasin: return new Color32(255, 228, 181, 255); case CustomColor.NavajoWhite: return new Color32(255, 222, 173, 255); case CustomColor.Navy: return new Color32(0, 0, 128, 255); case CustomColor.OldLace: return new Color32(253, 245, 230, 255); case CustomColor.Olive: return new Color32(128, 128, 0, 255); case CustomColor.Olivedrab: return new Color32(107, 142, 35, 255); case CustomColor.Orange: return new Color32(255, 165, 0, 255); case CustomColor.Orangered: return new Color32(255, 69, 0, 255); case CustomColor.Orchid: return new Color32(218, 112, 214, 255); case CustomColor.PaleGoldenrod: return new Color32(238, 232, 170, 255); case CustomColor.PaleGreen: return new Color32(152, 251, 152, 255); case CustomColor.PaleTurquoise: return new Color32(175, 238, 238, 255); case CustomColor.PaleVioletred: return new Color32(219, 112, 147, 255); case CustomColor.PapayaWhip: return new Color32(255, 239, 213, 255); case CustomColor.PeachPuff: return new Color32(255, 218, 185, 255); case CustomColor.Peru: return new Color32(205, 133, 63, 255); case CustomColor.Pink: return new Color32(255, 192, 203, 255); case CustomColor.Plum: return new Color32(221, 160, 221, 255); case CustomColor.PowderBlue: return new Color32(176, 224, 230, 255); case CustomColor.Purple: return new Color32(128, 0, 128, 255); case CustomColor.Red: return new Color32(255, 0, 0, 255); case CustomColor.RosyBrown: return new Color32(188, 143, 143, 255); case CustomColor.RoyalBlue: return new Color32(65, 105, 225, 255); case CustomColor.SaddleBrown: return new Color32(139, 69, 19, 255); case CustomColor.Salmon: return new Color32(250, 128, 114, 255); case CustomColor.SandyBrown: return new Color32(244, 164, 96, 255); case CustomColor.SeaGreen: return new Color32(46, 139, 87, 255); case CustomColor.Seashell: return new Color32(255, 245, 238, 255); case CustomColor.Sienna: return new Color32(160, 82, 45, 255); case CustomColor.Silver: return new Color32(192, 192, 192, 255); case CustomColor.SkyBlue: return new Color32(135, 206, 235, 255); case CustomColor.SlateBlue: return new Color32(106, 90, 205, 255); case CustomColor.SlateGray: return new Color32(112, 128, 144, 255); case CustomColor.Snow: return new Color32(255, 250, 250, 255); case CustomColor.SpringGreen: return new Color32(0, 255, 127, 255); case CustomColor.SteelBlue: return new Color32(70, 130, 180, 255); case CustomColor.Tan: return new Color32(210, 180, 140, 255); case CustomColor.Teal: return new Color32(0, 128, 128, 255); case CustomColor.Thistle: return new Color32(216, 191, 216, 255); case CustomColor.Tomato: return new Color32(255, 99, 71, 255); case CustomColor.Turquoise: return new Color32(64, 224, 208, 255); case CustomColor.Violet: return new Color32(238, 130, 238, 255); case CustomColor.Wheat: return new Color32(245, 222, 179, 255); case CustomColor.White: return new Color32(255, 255, 255, 255); case CustomColor.WhiteSmoke: return new Color32(245, 245, 245, 255); case CustomColor.Yellow: return new Color32(255, 255, 0, 255); case CustomColor.YellowGreen: return new Color32(154, 205, 50, 255); case CustomColor.BlueVariant: return new Color32(67, 110, 238, 255); case CustomColor.Bright: return new Color32(196, 196, 196, 255); case CustomColor.DarkOlive: return new Color32(47, 79, 79, 255); case CustomColor.OrangeVariant: return new Color32(255, 135, 62, 255); case CustomColor.LightRed: return new Color32(217, 71, 71, 255); case CustomColor.RedVariant: return new Color32(232, 10, 10, 255); default: return new Color32(0, 0, 0, 0); } } } public enum CustomColor { AliceBlue, AntiqueWhite, Aqua, Aquamarine, Azure, Beige, Bisque, Black, BlanchedAlmond, Blue, BlueViolet, BlueVariant, Brown, Burlywood, Bright, CadetBlue, Chartreuse, Chocolate, Coral, CornflowerBlue, Cornsilk, Crimson, Cyan, DarkBlue, DarkCyan, DarkGoldenrod, DarkGray, DarkGreen, DarkKhaki, DarkMagenta, DarkOlive, DarkOliveGreen, DarkOrange, DarkOrchid, DarkRed, DarkSalmon, DarkSeaGreen, DarkSlateBlue, DarkSlateGray, DarkTurquoise, DarkViolet, DeepPink, DeepSkyBlue, DimGray, DodgerBlue, FireBrick, FloralWhite, ForestGreen, Fuchsia, Gainsboro, GhostWhite, Gold, Goldenrod, Gray, Green, GreenYellow, Honeydew, HotPink, IndianRed, Indigo, Ivory, Khaki, Lavender, Lavenderblush, LawnGreen, LemonChiffon, LightBlue, LightCoral, LightCyan, LightGoldenodYellow, LightGray, LightGreen, LightPink, LightRed, LightSalmon, LightSeaGreen, LightSkyBlue, LightSlateGray, LightSteelBlue, LightYellow, Lime, LimeGreen, Linen, Magenta, Maroon, MediumAquamarine, MediumBlue, MediumOrchid, MediumPurple, MediumSeaGreen, MediumSlateBlue, MediumSpringGreen, MediumTurquoise, MediumVioletRed, MidnightBlue, Mintcream, MistyRose, Moccasin, NavajoWhite, Navy, OldLace, Olive, Olivedrab, Orange, Orangered, OrangeVariant, Orchid, PaleGoldenrod, PaleGreen, PaleTurquoise, PaleVioletred, PapayaWhip, PeachPuff, Peru, Pink, Plum, PowderBlue, Purple, Red, RedVariant, RosyBrown, RoyalBlue, SaddleBrown, Salmon, SandyBrown, SeaGreen, Seashell, Sienna, Silver, SkyBlue, SlateBlue, SlateGray, Snow, SpringGreen, SteelBlue, Tan, Teal, Thistle, Tomato, Turquoise, Violet, Wheat, White, WhiteSmoke, Yellow, YellowGreen, } } ================================================ FILE: VirtueSky/Utils/Runtime/ColorExtensions.cs.meta ================================================ fileFormatVersion: 2 guid: 8eaf9fcfd2284c44971d398f8fc71851 timeCreated: 1700209802 ================================================ FILE: VirtueSky/Utils/Runtime/ExtensionUtils.cs ================================================ using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; using UnityEditor; using UnityEngine; using UnityEngine.AI; using UnityEngine.Networking; namespace VirtueSky.Utils { public static class MonoBehaviorExtension { public static Coroutine Delay(this MonoBehaviour mono, float time, bool realTime, System.Action callback) { return mono.StartCoroutine(WaitForExtraTime(time, realTime, callback)); } static IEnumerator WaitForExtraTime(float time, bool realTime, System.Action callback) { if (realTime) { yield return new WaitForSecondsRealtime(time); } else { yield return new WaitForSeconds(time); } callback?.Invoke(); } public static Coroutine Delay(this MonoBehaviour mono, int frame, System.Action callback) { return mono.StartCoroutine(WaitForExtraFrame(frame, callback)); } static IEnumerator WaitForExtraFrame(int frame, System.Action callback) { for (var i = 0; i < frame; i++) { yield return null; } callback?.Invoke(); } public static Coroutine WaitUntil(this MonoBehaviour mono, Func condition, Action callback) { return mono.StartCoroutine(WaitUntil(condition, callback)); } static IEnumerator WaitUntil(Func condition, Action callback) { yield return new WaitUntil(condition); callback?.Invoke(); } public static T GetAndCacheComponent(this MonoBehaviour mono, ref T cache) where T : Component { return cache ? cache : (cache = mono.GetComponent()); } public static T GetAndCacheComponentInChildren(this MonoBehaviour mono, ref T cache, bool includeInactive = false) { return cache ??= mono.GetComponentInChildren(includeInactive); } public static T[] GetAndCacheComponents(this MonoBehaviour mono, ref T[] cache) where T : Component { return cache ??= mono.GetComponents(); } public static T[] GetAndCacheComponentsInChildren(this MonoBehaviour mono, ref T[] cache, bool includeInactive = false) { return cache ??= mono.GetComponentsInChildren(includeInactive); } public static T GetAndCacheComponentInParent(this MonoBehaviour mono, ref T cache) { return cache ??= mono.GetComponentInParent(); } } public static class GameObjectExtension { static List m_ComponentCache = new List(); public static Component GetComponentNoAlloc(this GameObject go, System.Type componentType) { go.GetComponents(componentType, m_ComponentCache); var component = m_ComponentCache.Count > 0 ? m_ComponentCache[0] : null; m_ComponentCache.Clear(); return component; } public static T GetComponentNoAlloc(this GameObject go) where T : Component { go.GetComponents(typeof(T), m_ComponentCache); var component = m_ComponentCache.Count > 0 ? m_ComponentCache[0] : null; m_ComponentCache.Clear(); return component as T; } public static T GetAndCacheComponent(this GameObject go, ref T cache) { return cache ??= go.GetComponent(); } public static T GetAndCacheComponentInChildren(this GameObject go, bool includeInactive, ref T cache) { return cache ??= go.GetComponentInChildren(includeInactive); } } public static class TransformExtensions { public static void RandomRotation(this Transform transform, bool onlyY = false) { transform.rotation = SimpleMath.RandomRotation(onlyY); } public static void RandomLocalRotation(this Transform transform, bool onlyY = false) { transform.localRotation = SimpleMath.RandomRotation(onlyY); } public static void Copy(this Transform transform, Transform other, bool position, bool rotation, bool scale, bool otherLossyScale) { if (position) transform.position = other.transform.position; if (rotation) transform.rotation = other.transform.rotation; if (scale) { transform.localScale = otherLossyScale ? other.transform.lossyScale : other.transform.localScale; } } public static void ResetLocal(this Transform transform) { transform.localPosition = Vector3.zero; transform.localRotation = Quaternion.identity; } // public static Tween DORotateQuaternionXZ(this Transform transform, Vector3 pos, float duration) // { // var dir = pos - transform.position; // dir.y = 0; // return transform.DORotateQuaternion(Quaternion.LookRotation(dir), duration); // } public static Vector2 position2D(this Transform transform) { return transform.position; } public static Vector2 localPosition2D(this Transform transform) { return transform.localPosition; } public static Bounds GetBounds(this Transform transform) { var bound = new Bounds(); var renderers = transform.GetComponentsInChildren().Where(r => !(r is ParticleSystemRenderer)).ToArray(); for (var j = 0; j < renderers.Length; j++) { if (j == 0) bound = renderers[j].bounds; else bound.Encapsulate(renderers[j].bounds); } return bound; } #if UNITY_EDITOR [MenuItem("CONTEXT/Transform/ExpandX")] public static void ExpandX(MenuCommand command) { var tfs = Selection.gameObjects.Select(g => g.transform).OrderBy(t => t.position.x).ToArray(); if (tfs.Length > 2) { Undo.RecordObjects(tfs, "ExpandX"); var min = tfs[0].position.x; var max = tfs[tfs.Length - 1].position.x; var step = (max - min) / (tfs.Length - 1); for (var i = 0; i < tfs.Length; i++) { var pos = tfs[i].position; pos.x = min + step * i; tfs[i].position = pos; EditorUtility.SetDirty(tfs[i]); } } } [MenuItem("CONTEXT/Transform/ExpandY")] public static void ExpandY(MenuCommand command) { var tfs = Selection.gameObjects.Select(g => g.transform).OrderBy(t => t.position.y).ToArray(); if (tfs.Length > 2) { Undo.RecordObjects(tfs, "ExpandY"); var min = tfs[0].position.y; var max = tfs[tfs.Length - 1].position.y; var step = (max - min) / (tfs.Length - 1); for (var i = 0; i < tfs.Length; i++) { var pos = tfs[i].position; pos.y = min + step * i; tfs[i].position = pos; EditorUtility.SetDirty(tfs[i]); } } } [MenuItem("CONTEXT/Transform/SetX")] public static void SetX(MenuCommand command) { var tfs = Selection.gameObjects.Select(g => g.transform).OrderBy(t => t.position.x).ToArray(); if (tfs.Length > 2) { Undo.RecordObjects(tfs, "SetX"); var startX = tfs[0].position.x; var prevBound = tfs[0].GetBounds(); for (var i = 0; i < tfs.Length; i++) { var dist = 0f; if (i > 0) { var bounds = tfs[i].GetBounds(); dist = prevBound.extents.x + bounds.extents.x; prevBound = bounds; } var pos = tfs[i].position; pos.x = startX + dist; tfs[i].position = pos; startX = pos.x; EditorUtility.SetDirty(tfs[i]); } } } [MenuItem("CONTEXT/Transform/SetY")] public static void SetY(MenuCommand command) { var tfs = Selection.gameObjects.Select(g => g.transform).OrderBy(t => t.position.y).ToArray(); if (tfs.Length > 2) { Undo.RecordObjects(tfs, "SetY"); var startY = tfs[0].position.y; var prevBound = tfs[0].GetBounds(); for (var i = 0; i < tfs.Length; i++) { var dist = 0f; if (i > 0) { var bounds = tfs[i].GetBounds(); dist = prevBound.extents.y + bounds.extents.y; prevBound = bounds; } var pos = tfs[i].position; pos.y = startY + dist; tfs[i].position = pos; startY = pos.y; EditorUtility.SetDirty(tfs[i]); } } } [MenuItem("CONTEXT/Transform/AlignX")] public static void AlignX(MenuCommand command) { var tfs = Selection.gameObjects.Select(g => g.transform).OrderBy(t => t.position.x).ToArray(); if (tfs.Length > 2) { Undo.RecordObjects(tfs, "AlignX"); var x = tfs[0].position.x; for (var i = 0; i < tfs.Length; i++) { var pos = tfs[i].position; pos.x = x; tfs[i].position = pos; EditorUtility.SetDirty(tfs[i]); } } } [MenuItem("CONTEXT/Transform/AlignY")] public static void AlignY(MenuCommand command) { var tfs = Selection.gameObjects.Select(g => g.transform).OrderBy(t => t.position.y).ToArray(); if (tfs.Length > 2) { Undo.RecordObjects(tfs, "AlignY"); var y = tfs[0].position.y; for (var i = 0; i < tfs.Length; i++) { var pos = tfs[i].position; pos.y = y; tfs[i].position = pos; EditorUtility.SetDirty(tfs[i]); } } } #endif } public static class LayerMaskExtension { public static int ToGameObjectLayer(this LayerMask layerMask) { return (int)Mathf.Log(layerMask.value, 2); } } public static class NavmeshExtension { public static bool IsReachDestination(this NavMeshAgent agent, float threshold = 0.1f) { return !agent.pathPending && agent.remainingDistance < agent.stoppingDistance + threshold; } } public static class EnumerationExtensions { public static bool Has(this Enum type, T value) { try { return (((int)(object)type & (int)(object)value) == (int)(object)value); } catch { return false; } } public static bool Is(this Enum type, T value) { try { return (int)(object)type == (int)(object)value; } catch { return false; } } public static T Add(this Enum type, T value) { try { return (T)(object)(((int)(object)type | (int)(object)value)); } catch (Exception ex) { throw new ArgumentException($"Could not append value from enumerated type '{typeof(T).Name}'.", ex); } } public static T Remove(this Enum type, T value) { try { return (T)(object)(((int)(object)type & ~(int)(object)value)); } catch (Exception ex) { throw new ArgumentException($"Could not remove value from enumerated type '{typeof(T).Name}'.", ex); } } } public static class MathExtension { public static System.Numerics.Vector3 ToSysVector3(this Vector3 v) { return new System.Numerics.Vector3(v.x, v.y, v.z); } public static System.Numerics.Quaternion ToSysQuaternion(this Quaternion v) { return new System.Numerics.Quaternion(v.x, v.y, v.z, v.w); } } public static class ParticleExtension { public static void SetSortingOrder(this ParticleSystem particle, int sortingOrder) { var ps = particle.GetComponentsInChildren(); foreach (var p in ps) { var r = p.GetComponent(); r.sortingOrder += sortingOrder; } } public static void SetStopAction(this ParticleSystem particle, ParticleSystemStopAction stopAction) { var main = particle.main; main.stopAction = stopAction; } } public static class FlipXExtension { public static void FlipX(this Transform target) { var pos = target.localPosition; pos.x = -pos.x; target.localPosition = pos; var rot = target.localRotation; rot *= Quaternion.Euler(0, 0, rot.y * 2); target.localRotation = rot; } public static void FlipX(this PolygonCollider2D target) { var points = target.points; for (var i = 0; i < points.Length; i++) { points[i].x = -points[i].x; } target.points = points; } public static void FlipX(this HingeJoint2D target) { var motor = target.motor; motor.motorSpeed = -motor.motorSpeed; target.motor = motor; } public static void FlipX(this BoxCollider2D target) { var offset = target.offset; offset.x = -offset.x; target.offset = offset; } public static void FlipX(this WheelJoint2D target) { var motor = target.motor; motor.motorSpeed = -motor.motorSpeed; target.motor = motor; } #if UNITY_EDITOR [MenuItem("CONTEXT/PolygonCollider2D/FlipX")] static void PolygonCollider2DFlipX(MenuCommand command) { var target = (PolygonCollider2D)command.context; target.FlipX(); EditorUtility.SetDirty(target); } [MenuItem("CONTEXT/Transform/FlipX")] static void TransformFlipX(MenuCommand command) { var target = (Transform)command.context; target.FlipX(); EditorUtility.SetDirty(target); } [MenuItem("CONTEXT/HingeJoint2D/FlipX")] static void HingeJoint2DFlipX(MenuCommand command) { var target = (HingeJoint2D)command.context; target.FlipX(); EditorUtility.SetDirty(target); } [MenuItem("CONTEXT/BoxCollider2D/FlipX")] static void BoxCollider2DFlipX(MenuCommand command) { var target = (BoxCollider2D)command.context; target.FlipX(); EditorUtility.SetDirty(target); } [MenuItem("CONTEXT/WheelJoint2D/FlipX")] static void WheelJoint2DFlipX(MenuCommand command) { var target = (WheelJoint2D)command.context; target.FlipX(); EditorUtility.SetDirty(target); } #endif } public class UnityWebRequestAwaiter : INotifyCompletion { UnityWebRequestAsyncOperation ao; Action continuation; public UnityWebRequestAwaiter(UnityWebRequestAsyncOperation ao) { this.ao = ao; ao.completed += OnRequestCompleted; } public bool IsCompleted => ao.isDone; public void GetResult() { } public void OnCompleted(Action c) { continuation = c; } void OnRequestCompleted(AsyncOperation obj) { continuation(); } } public static class UnityWebRequestExtensions { public static UnityWebRequestAwaiter GetAwaiter(this UnityWebRequestAsyncOperation asyncOp) { return new UnityWebRequestAwaiter(asyncOp); } } public static class DictionaryExtension { public static Dictionary Clone(this Dictionary dict) { if (dict == null) { return null; } return dict.ToDictionary(i => i.Key, i => i.Value); } public static string ToString(this Dictionary dict) { if (dict == null) { return string.Empty; } return string.Join(", ", dict); } } } ================================================ FILE: VirtueSky/Utils/Runtime/ExtensionUtils.cs.meta ================================================ fileFormatVersion: 2 guid: d424096a405f4d10b578a33d12c66fd1 timeCreated: 1622039108 ================================================ FILE: VirtueSky/Utils/Runtime/InputUtils.cs ================================================ using System.Collections.Generic; using UnityEngine; using UnityEngine.EventSystems; namespace VirtueSky.Utils { public class InputUtils { public static bool IsPointerOverUI(Vector2 pos) { var eventDataCurrentPosition = new PointerEventData(EventSystem.current) { position = new Vector2(pos.x, pos.y) }; var results = new List(); EventSystem.current.RaycastAll(eventDataCurrentPosition, results); return results.Count > 0; } } } ================================================ FILE: VirtueSky/Utils/Runtime/InputUtils.cs.meta ================================================ fileFormatVersion: 2 guid: b6fe19d3e11140659ebed2c0c0ef0ac1 timeCreated: 1630517731 ================================================ FILE: VirtueSky/Utils/Runtime/InterfaceUtils.cs ================================================ using System.Collections.Generic; using UnityEngine.SceneManagement; namespace VirtueSky.Utils { public static class InterfaceUtils { public static List GetAllInterfaces() { var interfaces = new List(); var rootGameObjects = SceneManager.GetActiveScene().GetRootGameObjects(); foreach (var rootGameObject in rootGameObjects) { var childrenInterfaces = rootGameObject.GetComponentsInChildren(true); foreach (var childInterface in childrenInterfaces) { interfaces.Add(childInterface); } } return interfaces; } } } ================================================ FILE: VirtueSky/Utils/Runtime/InterfaceUtils.cs.meta ================================================ fileFormatVersion: 2 guid: f38899acc2024dee8832c6a518563565 timeCreated: 1631162887 ================================================ FILE: VirtueSky/Utils/Runtime/ReflectionUtils.cs ================================================ using System; using System.Reflection; namespace VirtueSky.Utils { public static class ReflectionUtils { public static FieldInfo GetFieldRecursive(this Type type, string fieldName, BindingFlags bindingFlags) { var t = type; FieldInfo field = null; while (t != null) { field = t.GetField(fieldName, bindingFlags); if (field != null) break; t = t.BaseType; } return field; } } } ================================================ FILE: VirtueSky/Utils/Runtime/ReflectionUtils.cs.meta ================================================ fileFormatVersion: 2 guid: e093744796dd4fd19982333ec51c2ec5 timeCreated: 1658972648 ================================================ FILE: VirtueSky/Utils/Runtime/ScriptableSettings.cs ================================================ namespace VirtueSky.Utils { using UnityEngine; using System; public abstract class ScriptableSettings : ScriptableObject where T : ScriptableObject { private static T instance; public static T Instance { get { if (instance != null) return instance; instance = Resources.Load(typeof(T).Name); if (instance == null) throw new Exception($"Scriptable setting for {typeof(T)} must be create before run!"); return instance; } } public static bool IsExist() => Resources.Load(typeof(T).Name) != null; } } ================================================ FILE: VirtueSky/Utils/Runtime/ScriptableSettings.cs.meta ================================================ fileFormatVersion: 2 guid: 8433fcf2c3af43109ba905de77e68443 timeCreated: 1697171918 ================================================ FILE: VirtueSky/Utils/Runtime/SimpleMath.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using UnityEngine; using Random = UnityEngine.Random; namespace VirtueSky.Utils { public static class SimpleMath { public static bool InRange(Vector3 p, Vector3 c, float r, out float sqrDst, bool compareY = false) { if (!compareY) p.y = c.y; sqrDst = SqrDist(p, c); return sqrDst <= r * r; } public static bool InRange(Vector3 p, Vector3 c, float r, bool compareY = false) { if (!compareY) p.y = c.y; var sqrDst = SqrDist(p, c); return sqrDst <= r * r; } public static bool InRange2D(Vector2 p, Vector2 c, float r) { var sqrDst = SqrDist(p, c); return sqrDst <= r * r; } public static float SqrDist(Vector3 a, Vector3 b) { return (a - b).sqrMagnitude; } public static Quaternion RandomRotation(bool onlyY = false) { if (onlyY) return Quaternion.Euler(0, Random.value * 360f, 0); return Quaternion.Euler(RandomVector3() * 180f); } public static Quaternion GetRotationXZ(Vector3 a, Vector3 b) { var dir = b - a; dir.y = 0; if (dir != Vector3.zero) { return Quaternion.LookRotation(dir); } else { return Quaternion.identity; } } public static Quaternion AngVelToDeriv(Quaternion current, Vector3 angVel) { var spin = new Quaternion(angVel.x, angVel.y, angVel.z, 0f); var result = spin * current; return new Quaternion(0.5f * result.x, 0.5f * result.y, 0.5f * result.z, 0.5f * result.w); } public static Vector3 DerivToAngVel(Quaternion current, Quaternion deriv) { var result = deriv * Quaternion.Inverse(current); return new Vector3(2f * result.x, 2f * result.y, 2f * result.z); } public static Quaternion IntegrateRotation(Quaternion rotation, Vector3 angularVelocity, float deltaTime) { if (deltaTime < Mathf.Epsilon) return rotation; var deriv = AngVelToDeriv(rotation, angularVelocity); var pred = new Vector4( rotation.x + deriv.x * deltaTime, rotation.y + deriv.y * deltaTime, rotation.z + deriv.z * deltaTime, rotation.w + deriv.w * deltaTime ).normalized; return new Quaternion(pred.x, pred.y, pred.z, pred.w); } public static Quaternion QuaternionSmoothDamp(Quaternion rot, Quaternion target, ref Quaternion deriv, float time) { if (Time.deltaTime < Mathf.Epsilon) return rot; // account for double-cover var dot = Quaternion.Dot(rot, target); var multi = dot > 0f ? 1f : -1f; target.x *= multi; target.y *= multi; target.z *= multi; target.w *= multi; // smooth damp (nlerp approx) var result = new Vector4( Mathf.SmoothDamp(rot.x, target.x, ref deriv.x, time), Mathf.SmoothDamp(rot.y, target.y, ref deriv.y, time), Mathf.SmoothDamp(rot.z, target.z, ref deriv.z, time), Mathf.SmoothDamp(rot.w, target.w, ref deriv.w, time) ).normalized; // ensure deriv is tangent var derivError = Vector4.Project(new Vector4(deriv.x, deriv.y, deriv.z, deriv.w), result); deriv.x -= derivError.x; deriv.y -= derivError.y; deriv.z -= derivError.z; deriv.w -= derivError.w; return new Quaternion(result.x, result.y, result.z, result.w); } public static Vector3 RandomVector3(bool zeroY = false) { var result = Random.insideUnitSphere; if (zeroY) result.y = 0; return result; } public static int GetNearestIndex(Vector3 p, float r, Vector3[] list, bool compareY = false) { var minDist = Mathf.Infinity; var index = -1; var dist = 0f; for (var i = 0; i < list.Length; i++) { if (InRange(p, list[i], r, out dist, compareY)) { if (dist <= minDist) { minDist = dist; index = i; } } } return index; } public static Vector3 RandomBetween(Vector3 a, Vector3 b) { return a + (b - a).normalized * Random.value * (b - a).magnitude; } public static string NewGuid() { var encoded = Convert.ToBase64String(System.Guid.NewGuid().ToByteArray()); encoded = encoded.Replace("/", "_").Replace("+", "-"); return encoded.Substring(0, 22); } public static Vector3 DirectionFromAngle(float angleInDegrees) { return new Vector3(Mathf.Sin(angleInDegrees * Mathf.Deg2Rad), 0, Mathf.Cos(angleInDegrees * Mathf.Deg2Rad)); } public static T[] SelectRandomFromArray(T[] items, int count) { if (items.Length < count) { return items; } var list = items.ToList(); var result = new T[count]; while (list.Count > 0 && count > 0) { count--; result[count] = list[Random.Range(0, list.Count)]; list.Remove(result[count]); } return result; } public static Vector3[] GetCirclePoint(Vector3 center, float radius, float step = 0.1f) { var points = new List(); var theta = 0f; var x = radius * Mathf.Cos(theta); var y = radius * Mathf.Sin(theta); points.Add(center + new Vector3(x, 0, y)); for (theta = step; theta < Mathf.PI * 2; theta += step) { x = radius * Mathf.Cos(theta); y = radius * Mathf.Sin(theta); points.Add(center + new Vector3(x, 0, y)); } return points.ToArray(); } public static bool LinePlaneIntersection(out Vector3 intersection, Vector3 linePoint, Vector3 lineVec, Vector3 planeNormal, Vector3 planePoint) { float length; float dotNumerator; float dotDenominator; Vector3 vector; intersection = Vector3.zero; //calculate the distance between the linePoint and the line-plane intersection point dotNumerator = Vector3.Dot((planePoint - linePoint), planeNormal); dotDenominator = Vector3.Dot(lineVec, planeNormal); //line and plane are not parallel if (dotDenominator != 0.0f) { length = dotNumerator / dotDenominator; //create a vector from the linePoint to the intersection point vector = SetVectorLength(lineVec, length); //get the coordinates of the line-plane intersection point intersection = linePoint + vector; return true; } //output not valid else { return false; } } public static bool AreLineSegmentsCrossing(Vector3 pointA1, Vector3 pointA2, Vector3 pointB1, Vector3 pointB2) { Vector3 closestPointA; Vector3 closestPointB; int sideA; int sideB; Vector3 lineVecA = pointA2 - pointA1; Vector3 lineVecB = pointB2 - pointB1; bool valid = ClosestPointsOnTwoLines(out closestPointA, out closestPointB, pointA1, lineVecA.normalized, pointB1, lineVecB.normalized); //lines are not parallel if (valid) { sideA = PointOnWhichSideOfLineSegment(pointA1, pointA2, closestPointA); sideB = PointOnWhichSideOfLineSegment(pointB1, pointB2, closestPointB); if ((sideA == 0) && (sideB == 0)) { return true; } else { return false; } } else { return false; } } public static bool ClosestPointsOnTwoLines(out Vector3 closestPointLine1, out Vector3 closestPointLine2, Vector3 linePoint1, Vector3 lineVec1, Vector3 linePoint2, Vector3 lineVec2) { closestPointLine1 = Vector3.zero; closestPointLine2 = Vector3.zero; float a = Vector3.Dot(lineVec1, lineVec1); float b = Vector3.Dot(lineVec1, lineVec2); float e = Vector3.Dot(lineVec2, lineVec2); float d = a * e - b * b; //lines are not parallel if (d != 0.0f) { Vector3 r = linePoint1 - linePoint2; float c = Vector3.Dot(lineVec1, r); float f = Vector3.Dot(lineVec2, r); float s = (b * f - c * e) / d; float t = (a * f - c * b) / d; closestPointLine1 = linePoint1 + lineVec1 * s; closestPointLine2 = linePoint2 + lineVec2 * t; return true; } else { return false; } } public static int PointOnWhichSideOfLineSegment(Vector3 linePoint1, Vector3 linePoint2, Vector3 point) { Vector3 lineVec = linePoint2 - linePoint1; Vector3 pointVec = point - linePoint1; float dot = Vector3.Dot(pointVec, lineVec); //point is on side of linePoint2, compared to linePoint1 if (dot > 0) { //point is on the line segment if (pointVec.magnitude <= lineVec.magnitude) { return 0; } //point is not on the line segment and it is on the side of linePoint2 else { return 2; } } //Point is not on side of linePoint2, compared to linePoint1. //Point is not on the line segment and it is on the side of linePoint1. else { return 1; } } public static Vector3 SetVectorLength(Vector3 vector, float size) { //normalize the vector var vectorNormalized = Vector3.Normalize(vector); //scale the vector return vectorNormalized *= size; } public static Color DotColor(Color a, Color b) { var vA = new Vector3(a.r, a.g, a.b); var vB = new Vector3(b.r, b.g, b.b); var vC = Vector3.Dot(vA, vB); return new Color(vC, vC, vC); } public static T GetRandomWithWeight(T[] items, int[] weights) { var totalWeight = weights.Sum(); var rd = Random.Range(0, totalWeight); var sumWeight = 0; var result = items[0]; for (var i = 0; i < items.Length; i++) { sumWeight += weights[i]; if (rd < sumWeight) { result = items[i]; break; } } return result; } } } ================================================ FILE: VirtueSky/Utils/Runtime/SimpleMath.cs.meta ================================================ fileFormatVersion: 2 guid: 596eb1042e0345789ff57fc696c2de73 timeCreated: 1598278587 ================================================ FILE: VirtueSky/Utils/Runtime/StoreUtils.cs ================================================ using UnityEngine; namespace VirtueSky.Utils { public static class StoreUtils { public static void OpenStore() { #if UNITY_ANDROID Application.OpenURL($"market://details?id={Application.identifier}"); #elif UNITY_IPHONE Application.OpenURL("itms-apps://itunes.apple.com/app/1598593737"); #endif } } } ================================================ FILE: VirtueSky/Utils/Runtime/StoreUtils.cs.meta ================================================ fileFormatVersion: 2 guid: 95bee5da44516954396fb291ece7ae5f MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Runtime/TimeUtils.cs ================================================ using System; namespace VirtueSky.Utils { public static class TimeUtils { public static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0); public static readonly DateTime EpochUtc = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); public static DateTime Now => DateTime.Now; public static long CurrentTicks => DateTime.Now.Ticks - Epoch.Ticks; public static long CurrentTicksUtc => DateTime.UtcNow.Ticks - EpochUtc.Ticks; public static long CurrentDays => CurrentTicks / TimeSpan.TicksPerDay; public static double CurrentSeconds => TicksToSeconds(CurrentTicks); public static double CurrentSecondsUtc => TicksToSeconds(CurrentTicksUtc); public static DateTime TicksToDateTime(long ticks) { var date = Epoch + TimeSpan.FromTicks(ticks); return date.ToLocalTime(); } public static DateTime SecondsToDateTime(double seconds) { var date = Epoch + TimeSpan.FromSeconds(seconds); return date; } public static double TimespanSeconds(long ticks, long lastTicks) { return TimeSpan.FromTicks(ticks - lastTicks).TotalSeconds; } public static double TimespanHours(long ticks, long lastTicks) { return TimeSpan.FromTicks(ticks - lastTicks).TotalHours; } public static long SecondsToTicks(double seconds) { return (long)(seconds * TimeSpan.TicksPerSecond); } public static int SecondsToMiniseconds(double seconds) { return (int)(seconds * 1000); } public static double MinisecondsToSeconds(int miniseconds) { return (double)(miniseconds / 1000f); } public static double TicksToSeconds(long ticks) { return (double)ticks / TimeSpan.TicksPerSecond; } public static long SecondsToDays(double seconds) { return SecondsToTicks(seconds) / TimeSpan.TicksPerDay; } public static double DaysToSeconds(long days) { return TimeSpan.FromDays(days).TotalSeconds; } public static string FormatTimeSpan(double seconds) { var span = new TimeSpan(SecondsToTicks(seconds)); return span.Days > 0 ? $"{span.Days}:{span.Hours:00}:{span.Minutes:00}:{span.Seconds:00}" : span.Hours > 0 ? $"{span.Hours:00}:{span.Minutes:00}:{span.Seconds:00}" : $"{span.Minutes:00}:{span.Seconds:00}"; } public static string FormatTimeSpanExcludeSecond(double seconds) { var span = new TimeSpan(SecondsToTicks(seconds)); return span.Hours > 0 ? $"{span.Hours:00}h:{span.Minutes:00}min" : $"{span.Minutes:00}min"; } public static float TargetTimeScale { get; set; } = 1; } } ================================================ FILE: VirtueSky/Utils/Runtime/TimeUtils.cs.meta ================================================ fileFormatVersion: 2 guid: 56cb55840fb34aedb0e10253d754d60c timeCreated: 1596822219 ================================================ FILE: VirtueSky/Utils/Runtime/TweenStatic.cs ================================================ using System; using JetBrains.Annotations; namespace PrimeTween { public static class TweenStatic { // target, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime // target, startValue, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime #region EulerAngles public static Tween EulerAngles([NotNull] this UnityEngine.Transform target, UnityEngine.Vector3 startValue, UnityEngine.Vector3 endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.EulerAngles(target, startValue, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } public static Tween LocalEulerAngles([NotNull] this UnityEngine.Transform target, UnityEngine.Vector3 startValue, UnityEngine.Vector3 endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.LocalEulerAngles(target, startValue, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } #endregion #region Position public static Tween Position([NotNull] this UnityEngine.Transform target, UnityEngine.Vector3 endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.Position(target, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } public static Tween Position([NotNull] this UnityEngine.Transform target, UnityEngine.Vector3 startValue, UnityEngine.Vector3 endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.Position(target, startValue, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } public static Tween PositionAtSpeed([NotNull] this UnityEngine.Transform target, UnityEngine.Vector3 endValue, float averageSpeed, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.PositionAtSpeed(target, endValue, averageSpeed, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } public static Tween PositionAtSpeed([NotNull] this UnityEngine.Transform target, UnityEngine.Vector3 startValue, UnityEngine.Vector3 endValue, float averageSpeed, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.PositionAtSpeed(target, startValue, endValue, averageSpeed, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } // X public static Tween PositionX([NotNull] this UnityEngine.Transform target, Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.PositionX(target, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } public static Tween PositionX([NotNull] this UnityEngine.Transform target, Single startValue, Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.PositionX(target, startValue, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } // Y public static Tween PositionY([NotNull] this UnityEngine.Transform target, Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.PositionY(target, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } public static Tween PositionY([NotNull] this UnityEngine.Transform target, Single startValue, Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.PositionY(target, startValue, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } // Z public static Tween PositionZ([NotNull] this UnityEngine.Transform target, Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.PositionZ(target, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } public static Tween PositionZ([NotNull] this UnityEngine.Transform target, Single startValue, Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.PositionZ(target, startValue, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } #endregion #region Local Position public static Tween LocalPosition([NotNull] this UnityEngine.Transform target, UnityEngine.Vector3 endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.LocalPosition(target, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } public static Tween LocalPosition([NotNull] this UnityEngine.Transform target, UnityEngine.Vector3 startValue, UnityEngine.Vector3 endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.LocalPosition(target, startValue, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } public static Tween LocalPositionAtSpeed([NotNull] this UnityEngine.Transform target, UnityEngine.Vector3 endValue, float averageSpeed, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.LocalPositionAtSpeed(target, endValue, averageSpeed, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } public static Tween LocalPositionAtSpeed([NotNull] this UnityEngine.Transform target, UnityEngine.Vector3 startValue, UnityEngine.Vector3 endValue, float averageSpeed, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.LocalPositionAtSpeed(target, startValue, endValue, averageSpeed, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } // X public static Tween LocalPositionX([NotNull] this UnityEngine.Transform target, Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.LocalPositionX(target, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } public static Tween LocalPositionX([NotNull] this UnityEngine.Transform target, Single startValue, Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.LocalPositionX(target, startValue, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } // Y public static Tween LocalPositionY([NotNull] this UnityEngine.Transform target, Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.LocalPositionY(target, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } public static Tween LocalPositionY([NotNull] this UnityEngine.Transform target, Single startValue, Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.LocalPositionY(target, startValue, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } // Z public static Tween LocalPositionZ([NotNull] this UnityEngine.Transform target, Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.LocalPositionZ(target, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } public static Tween LocalPositionZ([NotNull] this UnityEngine.Transform target, Single startValue, Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.LocalPositionZ(target, startValue, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } #endregion #region Rotation public static Tween Rotation([NotNull] this UnityEngine.Transform target, UnityEngine.Vector3 endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.Rotation(target, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } public static Tween Rotation([NotNull] this UnityEngine.Transform target, UnityEngine.Vector3 startValue, UnityEngine.Vector3 endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.Rotation(target, startValue, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } public static Tween RotationAtSpeed([NotNull] this UnityEngine.Transform target, UnityEngine.Quaternion endValue, float averageAngularSpeed, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.RotationAtSpeed(target, endValue, averageAngularSpeed, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } public static Tween RotationAtSpeed([NotNull] this UnityEngine.Transform target, UnityEngine.Quaternion startValue, UnityEngine.Quaternion endValue, float averageAngularSpeed, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.RotationAtSpeed(target, startValue, endValue, averageAngularSpeed, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } #endregion #region Local Rotation public static Tween LocalRotation([NotNull] this UnityEngine.Transform target, UnityEngine.Vector3 endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.LocalRotation(target, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } public static Tween LocalRotation([NotNull] this UnityEngine.Transform target, UnityEngine.Vector3 startValue, UnityEngine.Vector3 endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.LocalRotation(target, startValue, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } public static Tween LocalRotationAtSpeed([NotNull] this UnityEngine.Transform target, UnityEngine.Quaternion endValue, float averageAngularSpeed, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.LocalRotationAtSpeed(target, endValue, averageAngularSpeed, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } public static Tween LocalRotationAtSpeed([NotNull] this UnityEngine.Transform target, UnityEngine.Quaternion startValue, UnityEngine.Quaternion endValue, float averageAngularSpeed, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.LocalRotationAtSpeed(target, startValue, endValue, averageAngularSpeed, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } #endregion #region Scale public static Tween Scale([NotNull] this UnityEngine.Transform target, UnityEngine.Vector3 startValue, UnityEngine.Vector3 endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.Scale(target, startValue, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } public static Tween Scale([NotNull] this UnityEngine.Transform target, UnityEngine.Vector3 endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.Scale(target, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } public static Tween ScaleX([NotNull] this UnityEngine.Transform target, Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.ScaleX(target, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } public static Tween ScaleX([NotNull] this UnityEngine.Transform target, Single startValue, Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.ScaleX(target, startValue, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } public static Tween ScaleY([NotNull] this UnityEngine.Transform target, Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.ScaleY(target, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } public static Tween ScaleY([NotNull] this UnityEngine.Transform target, Single startValue, Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.ScaleY(target, startValue, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } public static Tween ScaleZ([NotNull] this UnityEngine.Transform target, Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.ScaleZ(target, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } public static Tween ScaleZ([NotNull] this UnityEngine.Transform target, Single startValue, Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.ScaleZ(target, startValue, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } #endregion #region Color SpriteRenderer public static Tween Color([NotNull] this UnityEngine.SpriteRenderer target, UnityEngine.Color endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.Color(target, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } public static Tween Color([NotNull] this UnityEngine.SpriteRenderer target, UnityEngine.Color startValue, UnityEngine.Color endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.Color(target, startValue, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } public static Tween Alpha([NotNull] this UnityEngine.SpriteRenderer target, Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.Alpha(target, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } public static Tween Alpha([NotNull] this UnityEngine.SpriteRenderer target, Single startValue, Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.Alpha(target, startValue, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } #endregion #region Camera public static Tween CameraOrthographicSize([NotNull] this UnityEngine.Camera target, Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.CameraOrthographicSize(target, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } public static Tween CameraOrthographicSize([NotNull] this UnityEngine.Camera target, Single startValue, Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.CameraOrthographicSize(target, startValue, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } public static Tween CameraBackgroundColor([NotNull] this UnityEngine.Camera target, UnityEngine.Color endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.CameraBackgroundColor(target, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } public static Tween CameraBackgroundColor([NotNull] this UnityEngine.Camera target, UnityEngine.Color startValue, UnityEngine.Color endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.CameraBackgroundColor(target, startValue, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } public static Tween CameraAspect([NotNull] this UnityEngine.Camera target, Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.CameraAspect(target, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } public static Tween CameraAspect([NotNull] this UnityEngine.Camera target, Single startValue, Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.CameraAspect(target, startValue, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } public static Tween CameraFarClipPlane([NotNull] this UnityEngine.Camera target, Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.CameraFarClipPlane(target, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } public static Tween CameraFarClipPlane([NotNull] this UnityEngine.Camera target, Single startValue, Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.CameraFarClipPlane(target, startValue, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } public static Tween CameraFieldOfView([NotNull] this UnityEngine.Camera target, Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.CameraFieldOfView(target, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } public static Tween CameraFieldOfView([NotNull] this UnityEngine.Camera target, Single startValue, Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.CameraFieldOfView(target, startDelay, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } public static Tween CameraNearClipPlane([NotNull] this UnityEngine.Camera target, Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.CameraNearClipPlane(target, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } public static Tween CameraNearClipPlane([NotNull] this UnityEngine.Camera target, Single startvalue, Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.CameraNearClipPlane(target, startvalue, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } #endregion #region Color UI Graphic public static Tween Color([NotNull] this UnityEngine.UI.Graphic target, UnityEngine.Color endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.Color(target, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } public static Tween Color([NotNull] this UnityEngine.UI.Graphic target, UnityEngine.Color startValue, UnityEngine.Color endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.Color(target, startValue, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } public static Tween Alpha([NotNull] this UnityEngine.UI.Graphic target, Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.Alpha(target, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } public static Tween Alpha([NotNull] this UnityEngine.UI.Graphic target, Single startValue, Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.Alpha(target, startValue, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } #endregion #region UI Image public static Tween UIFillAmount([NotNull] this UnityEngine.UI.Image target, Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.UIFillAmount(target, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } public static Tween UIFillAmount([NotNull] this UnityEngine.UI.Image target, Single startValue, Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.UIFillAmount(target, startValue, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } #endregion #region Rigidbody public static Tween RigidbodyMovePosition([NotNull] this UnityEngine.Rigidbody target, UnityEngine.Vector3 endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.RigidbodyMovePosition(target, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } public static Tween RigidbodyMovePosition([NotNull] this UnityEngine.Rigidbody target, UnityEngine.Vector3 startValue, UnityEngine.Vector3 endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.RigidbodyMovePosition(target, startValue, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } public static Tween RigidbodyMoveRotation([NotNull] this UnityEngine.Rigidbody target, UnityEngine.Quaternion endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.RigidbodyMoveRotation(target, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } public static Tween RigidbodyMoveRotation([NotNull] this UnityEngine.Rigidbody target, UnityEngine.Quaternion startValue, UnityEngine.Quaternion endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.RigidbodyMoveRotation(target, startValue, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } #endregion #region Rigidbody2D public static Tween Rigidbody2DMovePosition([NotNull] this UnityEngine.Rigidbody2D target, UnityEngine.Vector2 endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.RigidbodyMovePosition(target, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } public static Tween Rigidbody2DMovePosition([NotNull] this UnityEngine.Rigidbody2D target, UnityEngine.Vector2 startValue, UnityEngine.Vector2 endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.RigidbodyMovePosition(target, startValue, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } public static Tween Rigidbody2DMoveRotation([NotNull] this UnityEngine.Rigidbody2D target, Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.RigidbodyMoveRotation(target, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } public static Tween Rigidbody2DMoveRotation([NotNull] this UnityEngine.Rigidbody2D target, Single startValue, Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.RigidbodyMoveRotation(target, startValue, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } #endregion #region Material public static Tween MaterialColor([NotNull] this UnityEngine.Material target, UnityEngine.Color endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.MaterialColor(target, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } public static Tween MaterialColor([NotNull] this UnityEngine.Material target, UnityEngine.Color startValue, UnityEngine.Color endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.MaterialColor(target, startValue, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } public static Tween MaterialAlpha([NotNull] this UnityEngine.Material target, Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.MaterialAlpha(target, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } public static Tween MaterialAlpha([NotNull] this UnityEngine.Material target, Single startValue, Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false) { return Tween.MaterialAlpha(target, startValue, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime); } #endregion } } ================================================ FILE: VirtueSky/Utils/Runtime/TweenStatic.cs.meta ================================================ fileFormatVersion: 2 guid: 738f4f5e3c9b4ab88264a46f0edf74b3 timeCreated: 1701418240 ================================================ FILE: VirtueSky/Utils/Runtime/Virtuesky.Sunflower.Utils.asmdef ================================================ { "name": "Virtuesky.Sunflower.Utils", "rootNamespace": "", "references": [ "GUID:80ecb87cae9c44d19824e70ea7229748" ], "includePlatforms": [], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], "versionDefines": [], "noEngineReferences": false } ================================================ FILE: VirtueSky/Utils/Runtime/Virtuesky.Sunflower.Utils.asmdef.meta ================================================ fileFormatVersion: 2 guid: c282fd4f3fc2c7540914e85842a013c7 AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Utils/Runtime.meta ================================================ fileFormatVersion: 2 guid: 770dace87f564d0faf67c561c84f0051 timeCreated: 1699932112 ================================================ FILE: VirtueSky/Utils.meta ================================================ fileFormatVersion: 2 guid: 2d0ca7a47dfd41541bb113dfd19ac5e8 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Variables/Editor/VariableGenerateGuid.cs ================================================ using System; using System.Collections.Generic; using UnityEditor; using UnityEngine; using VirtueSky.Core; using VirtueSky.UtilsEditor; namespace VirtueSky.Variables { internal class VariableGenerateGuid : AssetPostprocessor { private static readonly HashSet GuidsVariableCache = new HashSet(); private const string Key_Init_Session = "Key_Init_Session"; private static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths) { bool isInit = SessionState.GetBool(Key_Init_Session, false); if (!isInit) { CacheAllGuids(); SessionState.SetBool(Key_Init_Session, true); } else { OnImportAsset(importedAssets); OnAssetDeleted(deletedAssets); OnAssetMoved(movedFromAssetPaths, movedAssets); } } static void CacheAllGuids() { var baseVariables = FileExtension.FindAll(); foreach (var variable in baseVariables) { if (variable is IGuidVariable iGuidVariable) { iGuidVariable.Guid = GenerateGuid(variable); GuidsVariableCache.Add(iGuidVariable.Guid); } } } static void OnImportAsset(string[] importedAssets) { foreach (var path in importedAssets) { if (GuidsVariableCache.Contains(path)) continue; var asset = AssetDatabase.LoadAssetAtPath(path); if (asset == null || asset is not IGuidVariable iGuidVariable) continue; iGuidVariable.Guid = GenerateGuid(asset); GuidsVariableCache.Add(iGuidVariable.Guid); } } static void OnAssetDeleted(string[] deletedAssets) { foreach (var path in deletedAssets) { if (!GuidsVariableCache.Contains(path)) continue; GuidsVariableCache.Remove(path); } } static void OnAssetMoved(string[] movedFromAssetPaths, string[] movedAssets) { OnAssetDeleted(movedFromAssetPaths); OnImportAsset(movedAssets); } private static string GenerateGuid(ScriptableObject scriptableObject) { return AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(scriptableObject)); } } } ================================================ FILE: VirtueSky/Variables/Editor/VariableGenerateGuid.cs.meta ================================================ fileFormatVersion: 2 guid: 7dec4410dffa4b5dbb78a9f5ab26c621 timeCreated: 1717470269 ================================================ FILE: VirtueSky/Variables/Editor/VariableWindowEditor.cs ================================================ using Microsoft.Win32.SafeHandles; using UnityEditor; using VirtueSky.UtilsEditor; namespace VirtueSky.Variables { #if UNITY_EDITOR public class VariableWindowEditor : EditorWindow { #region Create ScriptableObject Variable private const string pathVariable = "/Variable"; private const string menuVariable = "Sunflower/Scriptable/Create Variable/"; [MenuItem(menuVariable + "Transform Variable", priority = 201)] public static void CreateVariableTransform() { var so = CreateAsset.CreateScriptableAssetsOnlyName(pathVariable, "so_transform_variable"); } [MenuItem(menuVariable + "Rect Variable", priority = 201)] public static void CreateVariableRect() { var so = CreateAsset.CreateScriptableAssetsOnlyName(pathVariable, "so_rect_variable"); } [MenuItem(menuVariable + "Object Variable", priority = 201)] public static void CreateVariableObject() { var so = CreateAsset.CreateScriptableAssetsOnlyName(pathVariable, "so_object_variables"); } [MenuItem(menuVariable + "Boolean Variable", priority = 201)] public static void CreateVariableBoolean() { var so = CreateAsset.CreateScriptableAssetsOnlyName(pathVariable, "so_bool_variables"); } [MenuItem(menuVariable + "Short Double Variable", priority = 201)] public static void CreateVariableShortDouble() { var so = CreateAsset.CreateScriptableAssetsOnlyName(pathVariable, "so_short_double_variable"); } [MenuItem(menuVariable + "Vector3 Variable", priority = 201)] public static void CreateVariableVector3() { var so = CreateAsset.CreateScriptableAssetsOnlyName(pathVariable, "so_vector3_variable"); } [MenuItem(menuVariable + "Vector2 Variable", priority = 201)] public static void CreateVariableVector2() { var so = CreateAsset.CreateScriptableAssetsOnlyName(pathVariable, "so_vector2_variable"); } [MenuItem(menuVariable + "String Variable", priority = 201)] public static void CreateVariableString() { var so = CreateAsset.CreateScriptableAssetsOnlyName(pathVariable, "so_string_variable"); } [MenuItem(menuVariable + "Float Variable", priority = 201)] public static void CreateVariableFloat() { var so = CreateAsset.CreateScriptableAssetsOnlyName(pathVariable, "so_float_variables"); } [MenuItem(menuVariable + "Integer Variable", priority = 201)] public static void CreateVariableInt() { var so = CreateAsset.CreateScriptableAssetsOnlyName(pathVariable, "so_int_variable"); } #endregion } #endif } ================================================ FILE: VirtueSky/Variables/Editor/VariableWindowEditor.cs.meta ================================================ fileFormatVersion: 2 guid: 8592c1130efe1ab448a38c88f5fa3145 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Variables/Editor/virtuesky.sunflower.variable.Editor.asmdef ================================================ { "name": "virtuesky.sunflower.variable.Editor", "rootNamespace": "", "references": [ "GUID:c904f6d969e991d459a0843b71c22ec5", "GUID:35d694408290717499b3838802212c7f", "GUID:bd40169efe8642149b1d2b72ba4903ce", "GUID:acb3cac55c622ec459c8caadf707623a", "GUID:540154dd0c5ed9a4dbbe695c402232fb" ], "includePlatforms": [ "Editor" ], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], "versionDefines": [], "noEngineReferences": false } ================================================ FILE: VirtueSky/Variables/Editor/virtuesky.sunflower.variable.Editor.asmdef.meta ================================================ fileFormatVersion: 2 guid: e0f213a0782f8f74b8e336c82c8f43b8 AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Variables/Editor.meta ================================================ fileFormatVersion: 2 guid: 35064efc1121d03469ef2454a60d7267 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Variables/Runtime/Base_Variable/BaseReference.cs ================================================ using System; using UnityEditor; using UnityEngine; #if UNITY_EDITOR #endif namespace VirtueSky.Variables { [Serializable] public class BaseReference : IReference { } [Serializable] public class BaseReference : BaseReference, IReference where TVariable : BaseVariable { [SerializeField] bool useVariable; [SerializeField] TType constantValue; [SerializeField] TVariable variable; public TType Value { get => useVariable ? variable.Value : constantValue; set { if (useVariable) { variable.Value = value; } else { constantValue = value; } } } public override string ToString() { return Value.ToString(); } } #if UNITY_EDITOR [CustomPropertyDrawer(typeof(BaseReference), true)] public sealed class BaseReferenceDrawer : PropertyDrawer { static readonly string[] popupOptions = { "Use Constant", "Use Variable" }; SerializedProperty property; SerializedProperty useVariable; SerializedProperty constantValue; SerializedProperty variable; public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { this.property = property; useVariable = property.FindPropertyRelative("useVariable"); constantValue = property.FindPropertyRelative("constantValue"); variable = property.FindPropertyRelative("variable"); var oldIndent = ResetIndent(); var fieldRect = DrawLabel(position, property, label); var valueRect = DrawField(position, fieldRect); DrawValue(position, valueRect); EndIndent(oldIndent); property.serializedObject.ApplyModifiedProperties(); } Rect DrawLabel(Rect position, SerializedProperty property, GUIContent label) { return EditorGUI.PrefixLabel(position, label); } Rect DrawField(Rect position, Rect fieldRect) { var buttonRect = GetPopupButtonRect(fieldRect); var valueRect = GetValueRect(fieldRect, buttonRect); var result = DrawPopupButton(buttonRect, useVariable.boolValue ? 1 : 0); useVariable.boolValue = result == 1; return valueRect; } void DrawValue(Rect position, Rect valueRect) { if (useVariable.boolValue) { EditorGUI.PropertyField(valueRect, variable, GUIContent.none); } else { DrawGenericPropertyField(position, valueRect); } } void DrawGenericPropertyField(Rect position, Rect valueRect) { EditorGUI.PropertyField(valueRect, constantValue, GUIContent.none); } int ResetIndent() { var indent = EditorGUI.indentLevel; EditorGUI.indentLevel = 0; return indent; } void EndIndent(int indent) { EditorGUI.indentLevel = indent; } int DrawPopupButton(Rect rect, int value) { return EditorGUI.Popup(rect, value, popupOptions, Styles.PopupStyle); } Rect GetValueRect(Rect fieldRect, Rect buttonRect) { var valueRect = new Rect(fieldRect); valueRect.x += buttonRect.width; valueRect.width -= buttonRect.width; return valueRect; } Rect GetPopupButtonRect(Rect fieldrect) { var buttonRect = new Rect(fieldrect); buttonRect.yMin += Styles.PopupStyle.margin.top; buttonRect.width = Styles.PopupStyle.fixedWidth + Styles.PopupStyle.margin.right; buttonRect.height = Styles.PopupStyle.fixedHeight + Styles.PopupStyle.margin.top; return buttonRect; } public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { return EditorGUIUtility.singleLineHeight; } static class Styles { static Styles() { PopupStyle = new GUIStyle(GUI.skin.GetStyle("PaneOptions")) { imagePosition = ImagePosition.ImageOnly, }; } public static GUIStyle PopupStyle { get; set; } } } #endif } ================================================ FILE: VirtueSky/Variables/Runtime/Base_Variable/BaseReference.cs.meta ================================================ fileFormatVersion: 2 guid: e2fd30b177734d4d8a02e823ec21b503 timeCreated: 1651588713 ================================================ FILE: VirtueSky/Variables/Runtime/Base_Variable/BaseVariable.cs ================================================ using System; using UnityEditor; using UnityEngine; using UnityEngine.Serialization; using VirtueSky.DataStorage; using VirtueSky.Events; using VirtueSky.Inspector; using VirtueSky.Utils; namespace VirtueSky.Variables { public class BaseVariable : BaseEvent, IVariable, ISerializationCallbackReceiver, IGuidVariable { [TitleColor("Id", CustomColor.Gold, CustomColor.Aqua), ShowIf(nameof(isSetData)), SerializeField] private TypeId typeId; [ShowIf(nameof(IsShowGuid)), ReadOnly, SerializeField] protected string guid; [ShowIf(nameof(IsShowCustomId)), SerializeField] private string customId; [TitleColor("Init value", CustomColor.Chartreuse, CustomColor.OrangeVariant), Tooltip("Set initial value for scriptable variable"), SerializeField] protected TType initializeValue; [TitleColor("Save Data", CustomColor.Tomato, CustomColor.MediumSpringGreen), Tooltip("Set data into dictionary, if not set data then scriptable variable will action as runtime variable"), SerializeField] protected bool isSetData; [Tooltip( "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"), ShowIf(nameof(isSetData)), SerializeField] protected bool isSaveData; [TitleColor("Raise event", CustomColor.DeepSkyBlue, CustomColor.Magenta), Tooltip("Raise event when value is changed"), SerializeField] protected bool isRaiseEvent; [NonSerialized] protected TType runtimeValue; #if UNITY_EDITOR [ShowIf(nameof(ConditionShow))] [ReadOnly, SerializeField] protected TType currentValue; #endif public TType InitializeValue => initializeValue; public string Guid { get => guid; set => guid = value; } public string CustomId { get => customId; set => customId = value; } public string Id => typeId switch { TypeId.Guid => guid, _ => customId, }; private void OnEnable() { #if UNITY_EDITOR currentValue = Value; #endif } public virtual TType Value { get => isSetData ? GameData.Get(Id, initializeValue) : runtimeValue; set { if (isSetData) { GameData.Set(Id, value); if (isSaveData) { GameData.Save(); } } else { runtimeValue = value; } #if UNITY_EDITOR currentValue = value; #endif if (isRaiseEvent) { Raise(value); } } } public void OnBeforeSerialize() { } public void OnAfterDeserialize() { runtimeValue = initializeValue; } public void ResetValue() { Value = initializeValue; } public override string ToString() { return Value.ToString(); } private bool IsShowGuid => isSetData && typeId == TypeId.Guid; private bool IsShowCustomId => isSetData && typeId == TypeId.CustomId; } public enum TypeId { Guid, CustomId } } ================================================ FILE: VirtueSky/Variables/Runtime/Base_Variable/BaseVariable.cs.meta ================================================ fileFormatVersion: 2 guid: 354f4bae410149e59e0ac1eec4ddc1e5 timeCreated: 1651587715 ================================================ FILE: VirtueSky/Variables/Runtime/Base_Variable/BaseVariableListener.cs ================================================ using System; using UnityEngine; using UnityEngine.Events; using VirtueSky.Events; namespace VirtueSky.Variables { public class BaseVariableListener : BaseEventListener where TEvent : BaseVariable where TResponse : UnityEvent { [SerializeField] private bool isRaisedOnStart; [SerializeField] private bool isRaisedOnEnable; private void Start() { if (isRaisedOnStart) { foreach (var t in listEventResponseDatas) { OnEventRaised(t.@event, t.@event.Value); } } } private void OnEnable() { if (isRaisedOnEnable) { foreach (var t in listEventResponseDatas) { OnEventRaised(t.@event, t.@event.Value); } } } } } ================================================ FILE: VirtueSky/Variables/Runtime/Base_Variable/BaseVariableListener.cs.meta ================================================ fileFormatVersion: 2 guid: 618fae92af2d4fd59f81d8f97daf73a6 timeCreated: 1660205495 ================================================ FILE: VirtueSky/Variables/Runtime/Base_Variable/IGuidVariable.cs ================================================ namespace VirtueSky.Variables { public interface IGuidVariable { string Guid { get; set; } } } ================================================ FILE: VirtueSky/Variables/Runtime/Base_Variable/IGuidVariable.cs.meta ================================================ fileFormatVersion: 2 guid: 616d5824d15f4a978da0254f5a5e52f2 timeCreated: 1717471847 ================================================ FILE: VirtueSky/Variables/Runtime/Base_Variable.meta ================================================ fileFormatVersion: 2 guid: 98e06be1c92b45a46a3457b3793ed394 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Variables/Runtime/Boolean_Variable/BooleanReference.cs ================================================ using System; namespace VirtueSky.Variables { [Serializable] public class BooleanReference : BaseReference { } } ================================================ FILE: VirtueSky/Variables/Runtime/Boolean_Variable/BooleanReference.cs.meta ================================================ fileFormatVersion: 2 guid: 5afc2b5361de44a59b143ce9db37d46f timeCreated: 1659149814 ================================================ FILE: VirtueSky/Variables/Runtime/Boolean_Variable/BooleanVariable.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Variables { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Variables/Boolean", fileName = "bool_variables")] [EditorIcon("scriptable_variable")] public class BooleanVariable : BaseVariable { public void Toggle() { Value = !Value; } } } ================================================ FILE: VirtueSky/Variables/Runtime/Boolean_Variable/BooleanVariable.cs.meta ================================================ fileFormatVersion: 2 guid: 8612af88fd55455ab06a565de64186b9 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 8f06818ab5c1c06439abc547979c8edd, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Variables/Runtime/Boolean_Variable/BooleanVariableListener.cs ================================================ using VirtueSky.Events; using VirtueSky.Inspector; namespace VirtueSky.Variables { [EditorIcon("scriptable_event_listener")] public class BooleanVariableListener : BaseVariableListener { } } ================================================ FILE: VirtueSky/Variables/Runtime/Boolean_Variable/BooleanVariableListener.cs.meta ================================================ fileFormatVersion: 2 guid: 4b3c2acc31f54b44bda55b648b827ab6 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 23cedf6c21faf0b4eb783f1fb5d4679a, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Variables/Runtime/Boolean_Variable.meta ================================================ fileFormatVersion: 2 guid: 2456a56fac0d9b44b97d3dd3a7b95a2c folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Variables/Runtime/Float_Variable/FloatReference.cs ================================================ using System; namespace VirtueSky.Variables { [Serializable] public class FloatReference : BaseReference { } } ================================================ FILE: VirtueSky/Variables/Runtime/Float_Variable/FloatReference.cs.meta ================================================ fileFormatVersion: 2 guid: 1e5ea93b60834733af1822c26b795c31 timeCreated: 1651588790 ================================================ FILE: VirtueSky/Variables/Runtime/Float_Variable/FloatVariable.cs ================================================ using UnityEngine; using VirtueSky.DataStorage; using VirtueSky.Inspector; namespace VirtueSky.Variables { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Variables/Float", fileName = "float_variables")] [EditorIcon("scriptable_variable")] public class FloatVariable : BaseVariable { [Tooltip("Clamps the value of this variable to a minimum and maximum.")] [SerializeField] private bool isClamped; [Tooltip("If clamped, sets the minimum and maximum")] [SerializeField, ShowIf(nameof(isClamped)), Indent] private Vector2 minMax = new(0, 100); public bool IsClamped => isClamped; public Vector2 MinMax { get => minMax; set => minMax = value; } public float Min { get => minMax.x; set => minMax.x = value; } public float Max { get => minMax.y; set => minMax.y = value; } public void Add(float value) { Value += value; } public override float Value { get => isSetData ? GameData.Get(Id, initializeValue) : runtimeValue; set { var clampedValue = IsClamped ? Mathf.Clamp(value, minMax.x, minMax.y) : value; if (isSetData) { GameData.Set(Id, clampedValue); if (isSaveData) { GameData.Save(); } } else { runtimeValue = clampedValue; } #if UNITY_EDITOR currentValue = clampedValue; #endif if (isRaiseEvent) { Raise(clampedValue); } } } } } ================================================ FILE: VirtueSky/Variables/Runtime/Float_Variable/FloatVariable.cs.meta ================================================ fileFormatVersion: 2 guid: e09883a9e2054c19929fd8b3292fa7d9 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 8f06818ab5c1c06439abc547979c8edd, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Variables/Runtime/Float_Variable/FloatVariableListener.cs ================================================ using VirtueSky.Events; using VirtueSky.Inspector; namespace VirtueSky.Variables { [EditorIcon("scriptable_event_listener")] public class FloatVariableListener : BaseVariableListener { } } ================================================ FILE: VirtueSky/Variables/Runtime/Float_Variable/FloatVariableListener.cs.meta ================================================ fileFormatVersion: 2 guid: a246834ae1b84ef38132800b51b86cfe MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 23cedf6c21faf0b4eb783f1fb5d4679a, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Variables/Runtime/Float_Variable.meta ================================================ fileFormatVersion: 2 guid: 490c536cfc45de945833bdbfddd86b24 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Variables/Runtime/Integer_Variable/IntegerReference.cs ================================================ using System; namespace VirtueSky.Variables { [Serializable] public class IntegerReference : BaseReference { } } ================================================ FILE: VirtueSky/Variables/Runtime/Integer_Variable/IntegerReference.cs.meta ================================================ fileFormatVersion: 2 guid: 4848f429140e4efcbf42ee9e910e9bb3 timeCreated: 1659595428 ================================================ FILE: VirtueSky/Variables/Runtime/Integer_Variable/IntegerVariable.cs ================================================ using UnityEngine; using VirtueSky.DataStorage; using VirtueSky.Inspector; namespace VirtueSky.Variables { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Variables/Integer", fileName = "int_variable")] [EditorIcon("scriptable_variable")] public class IntegerVariable : BaseVariable { [Tooltip("Clamps the value of this variable to a minimum and maximum.")] [SerializeField] private bool isClamped; public bool IsClamped => isClamped; [Tooltip("If clamped, sets the minimum and maximum")] [SerializeField, ShowIf(nameof(isClamped)), Indent] private Vector2Int minMax = new(0, 100); public Vector2Int MinMax { get => minMax; set => minMax = value; } public int Min { get => minMax.x; set => minMax.x = value; } public int Max { get => minMax.y; set => minMax.y = value; } public void Add(int value) { Value += value; } public override int Value { get => isSetData ? GameData.Get(Id, initializeValue) : runtimeValue; set { var clampedValue = IsClamped ? Mathf.Clamp(value, minMax.x, minMax.y) : value; if (isSetData) { GameData.Set(Id, clampedValue); if (isSaveData) { GameData.Save(); } } else { runtimeValue = clampedValue; } #if UNITY_EDITOR currentValue = clampedValue; #endif if (isRaiseEvent) { Raise(clampedValue); } } } } } ================================================ FILE: VirtueSky/Variables/Runtime/Integer_Variable/IntegerVariable.cs.meta ================================================ fileFormatVersion: 2 guid: c1e2751cf33a439b997c1f79b966df48 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 8f06818ab5c1c06439abc547979c8edd, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Variables/Runtime/Integer_Variable/IntegerVariableListener.cs ================================================ using VirtueSky.Events; using VirtueSky.Inspector; namespace VirtueSky.Variables { [EditorIcon("scriptable_event_listener")] public class IntegerVariableListener : BaseVariableListener { } } ================================================ FILE: VirtueSky/Variables/Runtime/Integer_Variable/IntegerVariableListener.cs.meta ================================================ fileFormatVersion: 2 guid: 3184f556234f4c47b9374467cd4afcef MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 23cedf6c21faf0b4eb783f1fb5d4679a, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Variables/Runtime/Integer_Variable.meta ================================================ fileFormatVersion: 2 guid: 8ec5b945a0d2f8048bbd2633196ea318 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Variables/Runtime/Interface_Variable/IReference.cs ================================================ namespace VirtueSky.Variables { public interface IReference { } public interface IReference : IReference { TType Value { get; set; } } } ================================================ FILE: VirtueSky/Variables/Runtime/Interface_Variable/IReference.cs.meta ================================================ fileFormatVersion: 2 guid: 651c592a5818b6b49bc85bab221450ba MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Variables/Runtime/Interface_Variable/IVariable.cs ================================================ namespace VirtueSky.Variables { public interface IVariable { TType Value { get; set; } } } ================================================ FILE: VirtueSky/Variables/Runtime/Interface_Variable/IVariable.cs.meta ================================================ fileFormatVersion: 2 guid: 271e3e5d558841141b076d69acb0b86b MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Variables/Runtime/Interface_Variable.meta ================================================ fileFormatVersion: 2 guid: 639bbfa8c84a0894a87097d6726e6c80 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Variables/Runtime/Object_Variable/ObjectReference.cs ================================================ using System; using Object = UnityEngine.Object; namespace VirtueSky.Variables { [Serializable] public class ObjectReference : BaseReference { } } ================================================ FILE: VirtueSky/Variables/Runtime/Object_Variable/ObjectReference.cs.meta ================================================ fileFormatVersion: 2 guid: 29476f09124c4a239c99d28185892add timeCreated: 1651594418 ================================================ FILE: VirtueSky/Variables/Runtime/Object_Variable/ObjectVariable.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Variables { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Variables/Object", fileName = "object_variables")] [EditorIcon("scriptable_variable")] public class ObjectVariable : BaseVariable { } } ================================================ FILE: VirtueSky/Variables/Runtime/Object_Variable/ObjectVariable.cs.meta ================================================ fileFormatVersion: 2 guid: 0a14f4e476834f9a917da6b6bf0b5d88 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 8f06818ab5c1c06439abc547979c8edd, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Variables/Runtime/Object_Variable/ObjectVariableListener.cs ================================================ using UnityEngine; using VirtueSky.Events; using VirtueSky.Inspector; namespace VirtueSky.Variables { [EditorIcon("scriptable_event_listener")] public class ObjectVariableListener : BaseVariableListener { } } ================================================ FILE: VirtueSky/Variables/Runtime/Object_Variable/ObjectVariableListener.cs.meta ================================================ fileFormatVersion: 2 guid: c6f3ceebb8874cd5aaa47c69b7b7c929 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 23cedf6c21faf0b4eb783f1fb5d4679a, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Variables/Runtime/Object_Variable.meta ================================================ fileFormatVersion: 2 guid: 4ce15af9d90474b46b95415565f6ccee folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Variables/Runtime/Rect_Variable/RectVariable.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Variables { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Variables/Rect", fileName = "rect_variable")] [EditorIcon("scriptable_variable")] public class RectVariable : BaseVariable { } } ================================================ FILE: VirtueSky/Variables/Runtime/Rect_Variable/RectVariable.cs.meta ================================================ fileFormatVersion: 2 guid: aa90022cc8bc365459867349d32fba34 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 8f06818ab5c1c06439abc547979c8edd, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Variables/Runtime/Rect_Variable.meta ================================================ fileFormatVersion: 2 guid: 54ead9d4353c75a439a658d6ad3b823b folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Variables/Runtime/ShortDouble_Variable/ShortDoubleReference.cs ================================================ using System; using VirtueSky.DataType; namespace VirtueSky.Variables { [Serializable] public class ShortDoubleReference : BaseReference { } } ================================================ FILE: VirtueSky/Variables/Runtime/ShortDouble_Variable/ShortDoubleReference.cs.meta ================================================ fileFormatVersion: 2 guid: 0e49dc8d16524024cb54cf7f9c0abea8 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Variables/Runtime/ShortDouble_Variable/ShortDoubleVariable.cs ================================================ using UnityEngine; using VirtueSky.DataType; using VirtueSky.Inspector; namespace VirtueSky.Variables { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Variables/ShortDouble", fileName = "short_double_variable")] [EditorIcon("scriptable_variable")] public class ShortDoubleVariable : BaseVariable { } } ================================================ FILE: VirtueSky/Variables/Runtime/ShortDouble_Variable/ShortDoubleVariable.cs.meta ================================================ fileFormatVersion: 2 guid: 4c151fa8c0723124eb8aedcc6c272839 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 8f06818ab5c1c06439abc547979c8edd, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Variables/Runtime/ShortDouble_Variable/ShortDoubleVariableListener.cs ================================================ using VirtueSky.DataType; using VirtueSky.Events; using VirtueSky.Inspector; namespace VirtueSky.Variables { [EditorIcon("scriptable_event_listener")] public class ShortDoubleVariableListener : BaseVariableListener { } } ================================================ FILE: VirtueSky/Variables/Runtime/ShortDouble_Variable/ShortDoubleVariableListener.cs.meta ================================================ fileFormatVersion: 2 guid: e1cc454b4a0e77b458061f8da8a844ca MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 23cedf6c21faf0b4eb783f1fb5d4679a, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Variables/Runtime/ShortDouble_Variable.meta ================================================ fileFormatVersion: 2 guid: 75035666cae3e504880746ddd42aa762 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Variables/Runtime/String_Variable/StringVariable.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Variables { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Variables/String", fileName = "string_variable")] [EditorIcon("scriptable_variable")] public class StringVariable : BaseVariable { } } ================================================ FILE: VirtueSky/Variables/Runtime/String_Variable/StringVariable.cs.meta ================================================ fileFormatVersion: 2 guid: ac78349e5fc985d48b9901f74f86c69c MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 8f06818ab5c1c06439abc547979c8edd, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Variables/Runtime/String_Variable/StringVariableListener.cs ================================================ using VirtueSky.Events; using VirtueSky.Inspector; namespace VirtueSky.Variables { [EditorIcon("scriptable_event_listener")] public class StringVariableListener : BaseVariableListener { } } ================================================ FILE: VirtueSky/Variables/Runtime/String_Variable/StringVariableListener.cs.meta ================================================ fileFormatVersion: 2 guid: 2205b9d988c5bbf41bcf05224141d0ac MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 23cedf6c21faf0b4eb783f1fb5d4679a, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Variables/Runtime/String_Variable.meta ================================================ fileFormatVersion: 2 guid: 54c0f56779550204881234dcc0693134 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Variables/Runtime/Trasform_Variable/TransformReference.cs ================================================ using System; using UnityEngine; namespace VirtueSky.Variables { [Serializable] public class TransformReference : BaseReference { } } ================================================ FILE: VirtueSky/Variables/Runtime/Trasform_Variable/TransformReference.cs.meta ================================================ fileFormatVersion: 2 guid: 09c1018d879b4836aa50590af7928614 timeCreated: 1663139158 ================================================ FILE: VirtueSky/Variables/Runtime/Trasform_Variable/TransformVariable.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Variables { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Variables/Transform", fileName = "transform_variable")] [EditorIcon("scriptable_variable")] public class TransformVariable : BaseVariable { } } ================================================ FILE: VirtueSky/Variables/Runtime/Trasform_Variable/TransformVariable.cs.meta ================================================ fileFormatVersion: 2 guid: 864f507d17eb4386b9d734dc4ac56fdc MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 8f06818ab5c1c06439abc547979c8edd, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Variables/Runtime/Trasform_Variable.meta ================================================ fileFormatVersion: 2 guid: fa13033c6458d384bbb6a6119e20de1d folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Variables/Runtime/Vector2_Variable/Vector2Reference.cs ================================================ using System; using UnityEngine; namespace VirtueSky.Variables { [Serializable] public class Vector2Reference : BaseReference { } } ================================================ FILE: VirtueSky/Variables/Runtime/Vector2_Variable/Vector2Reference.cs.meta ================================================ fileFormatVersion: 2 guid: f6daaded9fe84782a274c9eb90d2dfed timeCreated: 1757604090 ================================================ FILE: VirtueSky/Variables/Runtime/Vector2_Variable/Vector2Variable.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Variables { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Variables/Vector2", fileName = "vector2_variable")] [EditorIcon("scriptable_variable")] public class Vector2Variable : BaseVariable { } } ================================================ FILE: VirtueSky/Variables/Runtime/Vector2_Variable/Vector2Variable.cs.meta ================================================ fileFormatVersion: 2 guid: f8819a76c4614ce8b1e713e14a5b23f1 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 8f06818ab5c1c06439abc547979c8edd, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Variables/Runtime/Vector2_Variable/Vector2VariableListener.cs ================================================ using UnityEngine; using VirtueSky.Events; using VirtueSky.Inspector; namespace VirtueSky.Variables { [EditorIcon("scriptable_event_listener")] public class Vector2VariableListener : BaseVariableListener { } } ================================================ FILE: VirtueSky/Variables/Runtime/Vector2_Variable/Vector2VariableListener.cs.meta ================================================ fileFormatVersion: 2 guid: 0b20b9568db145829e3de8df138a96eb MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 23cedf6c21faf0b4eb783f1fb5d4679a, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Variables/Runtime/Vector2_Variable.meta ================================================ fileFormatVersion: 2 guid: 1f265618642f4328b6805b4f83450730 timeCreated: 1757603938 ================================================ FILE: VirtueSky/Variables/Runtime/Vector3_Variable/Vector3Reference.cs ================================================ using System; using UnityEngine; namespace VirtueSky.Variables { [Serializable] public class Vector3Reference : BaseReference { } } ================================================ FILE: VirtueSky/Variables/Runtime/Vector3_Variable/Vector3Reference.cs.meta ================================================ fileFormatVersion: 2 guid: c8538927a6f440d09b3d9bd721c98d03 timeCreated: 1659591686 ================================================ FILE: VirtueSky/Variables/Runtime/Vector3_Variable/Vector3Variable.cs ================================================ using UnityEngine; using VirtueSky.Inspector; namespace VirtueSky.Variables { [CreateAssetMenu(menuName = "Sunflower/Scriptable/Variables/Vector3", fileName = "vector3_variable")] [EditorIcon("scriptable_variable")] public class Vector3Variable : BaseVariable { public Vector2 ToVector2() { return new Vector2(Value.x, Value.y); } } } ================================================ FILE: VirtueSky/Variables/Runtime/Vector3_Variable/Vector3Variable.cs.meta ================================================ fileFormatVersion: 2 guid: 7f0af1c6a8c08dd488a31bebb5f99dd7 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 8f06818ab5c1c06439abc547979c8edd, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Variables/Runtime/Vector3_Variable/Vector3VariableListener.cs ================================================ using UnityEngine; using VirtueSky.Events; using VirtueSky.Inspector; namespace VirtueSky.Variables { [EditorIcon("scriptable_event_listener")] public class Vector3VariableListener : BaseVariableListener { } } ================================================ FILE: VirtueSky/Variables/Runtime/Vector3_Variable/Vector3VariableListener.cs.meta ================================================ fileFormatVersion: 2 guid: af20733a69844bfcac05756bcbafe724 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {fileID: 2800000, guid: 23cedf6c21faf0b4eb783f1fb5d4679a, type: 3} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Variables/Runtime/Vector3_Variable.meta ================================================ fileFormatVersion: 2 guid: 99bc37103839c5b43bce252133cb3c55 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Variables/Runtime/virtuesky.sunflower.variable.asmdef ================================================ { "name": "Virtuesky.Sunflower.Variable", "rootNamespace": "", "references": [ "GUID:bd40169efe8642149b1d2b72ba4903ce", "GUID:32dbaa332e571bf429b7de517f75f074", "GUID:acb3cac55c622ec459c8caadf707623a", "GUID:540154dd0c5ed9a4dbbe695c402232fb", "GUID:324caed91501a9c47a04ebfd87b68794", "GUID:c282fd4f3fc2c7540914e85842a013c7" ], "includePlatforms": [], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], "versionDefines": [], "noEngineReferences": false } ================================================ FILE: VirtueSky/Variables/Runtime/virtuesky.sunflower.variable.asmdef.meta ================================================ fileFormatVersion: 2 guid: 35d694408290717499b3838802212c7f AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Variables/Runtime.meta ================================================ fileFormatVersion: 2 guid: cbd685ee2f1327248b7fea9c1587ed6e folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Variables.meta ================================================ fileFormatVersion: 2 guid: 220c229567bfa014885a022face64260 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Vibration/Plugins/iOS/Vibration/HapticFeedback.mm ================================================ #import extern "C" { void _impactOccurred(const char *style) { UIImpactFeedbackStyle feedbackStyle; if (strcmp(style, "Heavy") == 0) feedbackStyle = UIImpactFeedbackStyleHeavy; else if (strcmp(style, "Medium") == 0) feedbackStyle = UIImpactFeedbackStyleMedium; else if (strcmp(style, "Light") == 0) feedbackStyle = UIImpactFeedbackStyleLight; else if (strcmp(style, "Rigid") == 0) if (@available(iOS 13.0, *)) { feedbackStyle = UIImpactFeedbackStyleRigid; } else { return; } else if (strcmp(style, "Soft") == 0) if (@available(iOS 13.0, *)) { feedbackStyle = UIImpactFeedbackStyleSoft; } else { return; } else return; UIImpactFeedbackGenerator *generator = [[UIImpactFeedbackGenerator alloc] initWithStyle:feedbackStyle]; [generator prepare]; [generator impactOccurred]; } void _notificationOccurred(const char *style) { UINotificationFeedbackType feedbackStyle; if (strcmp(style, "Error") == 0) feedbackStyle = UINotificationFeedbackTypeError; else if (strcmp(style, "Success") == 0) feedbackStyle = UINotificationFeedbackTypeSuccess; else if (strcmp(style, "Warning") == 0) feedbackStyle = UINotificationFeedbackTypeWarning; else return; UINotificationFeedbackGenerator *generator = [[UINotificationFeedbackGenerator alloc] init]; [generator prepare]; [generator notificationOccurred:feedbackStyle]; } void _selectionChanged() { UISelectionFeedbackGenerator *generator = [[UISelectionFeedbackGenerator alloc] init]; [generator prepare]; [generator selectionChanged]; } } ================================================ FILE: VirtueSky/Vibration/Plugins/iOS/Vibration/HapticFeedback.mm.meta ================================================ fileFormatVersion: 2 guid: 077b20d7b7a7dc14aafdb8363888b849 PluginImporter: externalObjects: {} serializedVersion: 2 iconMap: {} executionOrder: {} defineConstraints: [] isPreloaded: 0 isOverridable: 0 isExplicitlyReferenced: 0 validateReferences: 1 platformData: - first: Any: second: enabled: 0 settings: {} - first: Editor: Editor second: enabled: 0 settings: DefaultValueInitialized: true - first: iPhone: iOS second: enabled: 1 settings: {} - first: tvOS: tvOS second: enabled: 1 settings: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Vibration/Plugins/iOS/Vibration/Vibration.h ================================================ // // Vibration.h // https://videogamecreation.fr // // Created by Benoît Freslon on 23/03/2017. // Copyright © 2018 Benoît Freslon. All rights reserved. // #import @interface Vibration : NSObject ////////////////////////////////////////// #pragma mark - Vibrate + (BOOL) hasVibrator; + (void) vibrate; + (void) vibratePeek; + (void) vibratePop; + (void) vibrateNope; ////////////////////////////////////////// @end ================================================ FILE: VirtueSky/Vibration/Plugins/iOS/Vibration/Vibration.h.meta ================================================ fileFormatVersion: 2 guid: 83a187def68af42c29e1a38e747ea79a PluginImporter: externalObjects: {} serializedVersion: 2 iconMap: {} executionOrder: {} isPreloaded: 0 isOverridable: 0 platformData: - first: Any: second: enabled: 1 settings: {} - first: Editor: Editor second: enabled: 0 settings: DefaultValueInitialized: true userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Vibration/Plugins/iOS/Vibration/Vibration.mm ================================================ // // Vibration.mm // https://videogamecreation.fr // // Created by Benoît Freslon on 23/03/2017. // Copyright © 2018 Benoît Freslon. All rights reserved. // #import #import #import #import "Vibration.h" #define USING_IPAD UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad @interface Vibration () @end @implementation Vibration ////////////////////////////////////////// #pragma mark - Vibrate + (BOOL) hasVibrator { return !(USING_IPAD); } + (void) vibrate { AudioServicesPlaySystemSoundWithCompletion(1352, NULL); } + (void) vibratePeek { AudioServicesPlaySystemSoundWithCompletion(1519, NULL); // Actuate `Peek` feedback (weak boom) } + (void) vibratePop { AudioServicesPlaySystemSoundWithCompletion(1520, NULL); // Actuate `Pop` feedback (strong boom) } + (void) vibrateNope { AudioServicesPlaySystemSoundWithCompletion(1521, NULL); // Actuate `Nope` feedback (series of three weak booms) } @end ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #pragma mark - "C" extern "C" { ////////////////////////////////////////// // Vibrate bool _HasVibrator () { return [Vibration hasVibrator]; } void _Vibrate () { [Vibration vibrate]; } void _VibratePeek () { [Vibration vibratePeek]; } void _VibratePop () { [Vibration vibratePop]; } void _VibrateNope () { [Vibration vibrateNope]; } } ================================================ FILE: VirtueSky/Vibration/Plugins/iOS/Vibration/Vibration.mm.meta ================================================ fileFormatVersion: 2 guid: c31160a40d8f84d4395a22df26febd41 PluginImporter: externalObjects: {} serializedVersion: 2 iconMap: {} executionOrder: {} isPreloaded: 0 isOverridable: 0 platformData: - first: Any: second: enabled: 0 settings: {} - first: Editor: Editor second: enabled: 0 settings: DefaultValueInitialized: true - first: iPhone: iOS second: enabled: 1 settings: {} - first: tvOS: tvOS second: enabled: 1 settings: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Vibration/Plugins/iOS/Vibration.meta ================================================ fileFormatVersion: 2 guid: 3ee19d5b94e8d485d92b70732e586af5 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Vibration/Plugins/iOS.meta ================================================ fileFormatVersion: 2 guid: a8f7741f0c8fb4b3ebe08d51501d38aa folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Vibration/Plugins.meta ================================================ fileFormatVersion: 2 guid: 8a18a006579744750bc5f62a817c99ae folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Vibration/README.md ================================================ # Vibration Native **free** plugin for Unity for iOS and Android. Use custom vibrations on mobile. # Use ## Initialization Initialize the plugin with this line before using vibrations: `Vibration.Init();` ## Vibrations ### iOS and Android #### Default vibration Use `Vibration.Vibrate();` for a classic default ~400ms vibration #### Pop vibration Pop vibration: weak boom (For iOS: only available with the haptic engine. iPhone 6s minimum or Android) `Vibration.VibratePop();` #### Peek Vibration Peek vibration: strong boom (For iOS: only available on iOS with the haptic engine. iPhone 6s minimum or Android) `Vibration.VibratePeek();` #### Nope Vibration Nope vibration: series of three weak booms (For iOS: only available with the haptic engine. iPhone 6s minimum or Android) `Vibration.VibrateNope();` --- ## Android Only #### Custom duration in milliseconds `Vibration.Vibrate(500);` #### Pattern ``` long [] pattern = { 0, 1000, 1000, 1000, 1000 }; Vibration.Vibrate ( pattern, -1 ); ``` #### Cancel `Vibration.Cancel();` --- ## IOS only vibration using haptic engine `Vibration.VibrateIOS(ImpactFeedbackStyle.Light);` `Vibration.VibrateIOS(ImpactFeedbackStyle.Medium);` `Vibration.VibrateIOS(ImpactFeedbackStyle.Heavy);` `Vibration.VibrateIOS(ImpactFeedbackStyle.Rigid);` `Vibration.VibrateIOS(ImpactFeedbackStyle.Soft);` `Vibration.VibrateIOS(NotificationFeedbackStyle.Error);` `Vibration.VibrateIOS(NotificationFeedbackStyle.Success);` `Vibration.VibrateIOS(NotificationFeedbackStyle.Warning);` `Vibration.VibrateIOS_SelectionChanged();` ================================================ FILE: VirtueSky/Vibration/README.md.meta ================================================ fileFormatVersion: 2 guid: 2af140d82dd314cbcaf375375751fea9 TextScriptImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Vibration/Vibration.cs ================================================ //////////////////////////////////////////////////////////////////////////////// // // @author Benoît Freslon @benoitfreslon // https://github.com/BenoitFreslon/Vibration // https://benoitfreslon.com // //////////////////////////////////////////////////////////////////////////////// using System.Runtime.InteropServices.ComTypes; using UnityEngine; using VirtueSky.DataStorage; #if UNITY_IOS using System.Collections; using System.Runtime.InteropServices; #endif namespace VirtueSky.Vibration { public static class Vibration { #if UNITY_IOS [DllImport ( "__Internal" )] private static extern bool _HasVibrator (); [DllImport ( "__Internal" )] private static extern void _Vibrate (); [DllImport ( "__Internal" )] private static extern void _VibratePop (); [DllImport ( "__Internal" )] private static extern void _VibratePeek (); [DllImport ( "__Internal" )] private static extern void _VibrateNope (); [DllImport("__Internal")] private static extern void _impactOccurred(string style); [DllImport("__Internal")] private static extern void _notificationOccurred(string style); [DllImport("__Internal")] private static extern void _selectionChanged(); #endif #if UNITY_ANDROID public static AndroidJavaClass unityPlayer; public static AndroidJavaObject currentActivity; public static AndroidJavaObject vibrator; public static AndroidJavaObject context; public static AndroidJavaClass vibrationEffect; #endif private static bool initialized = false; public static bool EnableVibration { get => GameData.Get("ENABLE_VIBRATION", true); set => GameData.Set("ENABLE_VIBRATION", value); } public static void Init() { if (initialized) return; #if UNITY_ANDROID if (Application.isMobilePlatform) { unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"); currentActivity = unityPlayer.GetStatic("currentActivity"); vibrator = currentActivity.Call("getSystemService", "vibrator"); context = currentActivity.Call("getApplicationContext"); if (AndroidVersion >= 26) { vibrationEffect = new AndroidJavaClass("android.os.VibrationEffect"); } } #endif initialized = true; } public static void VibrateIOS(ImpactFeedbackStyle style) { if (Application.isMobilePlatform && EnableVibration) { #if UNITY_IOS _impactOccurred(style.ToString()); #endif } } public static void VibrateIOS(NotificationFeedbackStyle style) { if (Application.isMobilePlatform && EnableVibration) { #if UNITY_IOS _notificationOccurred(style.ToString()); #endif } } public static void VibrateIOS_SelectionChanged() { if (Application.isMobilePlatform && EnableVibration) { #if UNITY_IOS _selectionChanged(); #endif } } /// /// Tiny pop vibration /// public static void VibratePop() { if (Application.isMobilePlatform && EnableVibration) { #if UNITY_IOS _VibratePop (); #elif UNITY_ANDROID VibrateAndroid(50); #endif } } /// /// Small peek vibration /// public static void VibratePeek() { if (Application.isMobilePlatform && EnableVibration) { #if UNITY_IOS _VibratePeek (); #elif UNITY_ANDROID VibrateAndroid(100); #endif } } /// /// 3 small vibrations /// public static void VibrateNope() { if (Application.isMobilePlatform && EnableVibration) { #if UNITY_IOS _VibrateNope (); #elif UNITY_ANDROID long[] pattern = { 0, 50, 50, 50 }; VibrateAndroid(pattern, -1); #endif } } #if UNITY_ANDROID /// /// Only on Android /// https://developer.android.com/reference/android/os/Vibrator.html#vibrate(long) /// public static void VibrateAndroid(long milliseconds) { if (Application.isMobilePlatform && EnableVibration) { if (AndroidVersion >= 26) { AndroidJavaObject createOneShot = vibrationEffect.CallStatic("createOneShot", milliseconds, -1); vibrator.Call("vibrate", createOneShot); } else { vibrator.Call("vibrate", milliseconds); } } } /// /// Only on Android /// https://proandroiddev.com/using-vibrate-in-android-b0e3ef5d5e07 /// public static void VibrateAndroid(long[] pattern, int repeat) { if (Application.isMobilePlatform && EnableVibration) { if (AndroidVersion >= 26) { long[] amplitudes; AndroidJavaObject createWaveform = vibrationEffect.CallStatic("createWaveform", pattern, repeat); vibrator.Call("vibrate", createWaveform); } else { vibrator.Call("vibrate", pattern, repeat); } } } #endif /// ///Only on Android /// public static void CancelAndroid() { if (Application.isMobilePlatform) { #if UNITY_ANDROID vibrator.Call("cancel"); #endif } } public static bool HasVibrator() { if (Application.isMobilePlatform) { #if UNITY_ANDROID AndroidJavaClass contextClass = new AndroidJavaClass("android.content.Context"); string Context_VIBRATOR_SERVICE = contextClass.GetStatic("VIBRATOR_SERVICE"); AndroidJavaObject systemService = context.Call("getSystemService", Context_VIBRATOR_SERVICE); if (systemService.Call("hasVibrator")) { return true; } else { return false; } #elif UNITY_IOS return _HasVibrator (); #else return false; #endif } else { return false; } } public static void Vibrate() { #if UNITY_ANDROID || UNITY_IOS if (Application.isMobilePlatform && EnableVibration) { Handheld.Vibrate(); } #endif } public static int AndroidVersion { get { int iVersionNumber = 0; if (Application.platform == RuntimePlatform.Android) { string androidVersion = SystemInfo.operatingSystem; int sdkPos = androidVersion.IndexOf("API-"); iVersionNumber = int.Parse(androidVersion.Substring(sdkPos + 4, 2).ToString()); } return iVersionNumber; } } } public enum ImpactFeedbackStyle { Heavy, Medium, Light, Rigid, Soft } public enum NotificationFeedbackStyle { Error, Success, Warning } } ================================================ FILE: VirtueSky/Vibration/Vibration.cs.meta ================================================ fileFormatVersion: 2 guid: 9a1817bb553014d4c9a665d4fa202202 timeCreated: 1474899097 licenseType: Pro MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Vibration/virtuesky.sunflower.vibration.asmdef ================================================ { "name": "Virtuesky.Sunflower.Vibration", "rootNamespace": "", "references": [ "GUID:32dbaa332e571bf429b7de517f75f074" ], "includePlatforms": [], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], "versionDefines": [], "noEngineReferences": false } ================================================ FILE: VirtueSky/Vibration/virtuesky.sunflower.vibration.asmdef.meta ================================================ fileFormatVersion: 2 guid: bd0c6a52234db0b4db0b3a5ab149f81c AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky/Vibration.meta ================================================ fileFormatVersion: 2 guid: 416bc8852a98c49bbaa3260119445847 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: VirtueSky.meta ================================================ fileFormatVersion: 2 guid: 284b2e8243e944a4782887d76e984d71 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: package.json ================================================ { "name": "com.virtuesky.sunflower", "displayName": "Sunflower", "description": "Core ScriptableObject Architecture for building Unity games", "version": "3.5.5-preview", "unity": "2022.3", "category": "virtuesky", "author": { "name": "virtuesky", "email": "virtuesky.0520@gmail.com", "url": "https://github.com/VirtueSky" }, "license": "MIT", "keywords": [ "ScriptableObjectArchitecture", "ScriptableObject", "Architecture", "Unity" ], "dependencies": { "com.unity.serialization": "3.1.1", "com.unity.collections": "2.1.4", "com.unity.textmeshpro": "3.0.8", "com.unity.addressables": "1.21.21", "com.cysharp.unitask": "https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask#2.5.10", "com.kyrylokuzyk.primetween": "1.3.8" } } ================================================ FILE: package.json.meta ================================================ fileFormatVersion: 2 guid: 124b2d6d5f51c4f1f970cf0138354eb3 TextScriptImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: