238 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			238 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| #if UNITY_EDITOR
 | |
| 
 | |
| using System;
 | |
| using System.Collections.Generic;
 | |
| using System.IO;
 | |
| using System.Text.RegularExpressions;
 | |
| using UnityEditor;
 | |
| using UnityEngine;
 | |
| 
 | |
| using UnitySettingsProviderAttribute = UnityEditor.SettingsProviderAttribute;
 | |
| using UnitySettingsProvider = UnityEditor.SettingsProvider;
 | |
| using FishNet.Configuring;
 | |
| using System.Linq;
 | |
| 
 | |
| namespace FishNet.Editing.PrefabCollectionGenerator
 | |
| {
 | |
|     internal static class SettingsProvider
 | |
|     {
 | |
|         private static readonly Regex SlashRegex = new Regex(@"[\\//]");
 | |
| 
 | |
|         private static PrefabGeneratorConfigurations _settings;
 | |
| 
 | |
|         private static GUIContent _folderIcon;
 | |
|         private static GUIContent _deleteIcon;
 | |
| 
 | |
|         private static Vector2 _scrollVector;
 | |
| 
 | |
|         private static bool _showFolders;
 | |
| 
 | |
|         [UnitySettingsProvider]
 | |
|         private static UnitySettingsProvider Create()
 | |
|         {
 | |
|             return new UnitySettingsProvider("Project/Fish-Networking/Prefab Objects Generator", SettingsScope.Project)
 | |
|             {
 | |
|                 label = "Prefab Objects Generator",
 | |
| 
 | |
|                 guiHandler = OnGUI,
 | |
| 
 | |
|                 keywords = new string[]
 | |
|                 {
 | |
|                     "Fish",
 | |
|                     "Networking",
 | |
|                     "Prefab",
 | |
|                     "Objects",
 | |
|                     "Generator",
 | |
|                 },
 | |
|             };
 | |
|         }
 | |
| 
 | |
|         private static void OnGUI(string searchContext)
 | |
|         {
 | |
|             if (_settings == null)
 | |
|                 _settings = Configuration.Configurations.PrefabGenerator;
 | |
|             if (_folderIcon == null)
 | |
|                 _folderIcon = EditorGUIUtility.IconContent("d_FolderOpened Icon");
 | |
|             if (_deleteIcon == null)
 | |
|                 _deleteIcon = EditorGUIUtility.IconContent("P4_DeletedLocal");
 | |
| 
 | |
|             EditorGUI.BeginChangeCheck();
 | |
|             GUIStyle scrollViewStyle = new GUIStyle()
 | |
|             {
 | |
|                 padding = new RectOffset(10, 10, 10, 10),
 | |
|             };
 | |
| 
 | |
|             _scrollVector = EditorGUILayout.BeginScrollView(_scrollVector, scrollViewStyle);
 | |
| 
 | |
|             _settings.Enabled = EditorGUILayout.Toggle(ObjectNames.NicifyVariableName(nameof(_settings.Enabled)), _settings.Enabled);
 | |
|             _settings.LogToConsole = EditorGUILayout.Toggle(ObjectNames.NicifyVariableName(nameof(_settings.LogToConsole)), _settings.LogToConsole);
 | |
|             _settings.FullRebuild = EditorGUILayout.Toggle(ObjectNames.NicifyVariableName(nameof(_settings.FullRebuild)), _settings.FullRebuild);
 | |
|             _settings.SaveChanges = EditorGUILayout.Toggle(ObjectNames.NicifyVariableName(nameof(_settings.SaveChanges)), _settings.SaveChanges);
 | |
| 
 | |
|             GUILayoutOption iconWidthConstraint = GUILayout.MaxWidth(32.0f);
 | |
|             GUILayoutOption iconHeightConstraint = GUILayout.MaxHeight(EditorGUIUtility.singleLineHeight);
 | |
| 
 | |
|             EditorGUILayout.BeginHorizontal();
 | |
| 
 | |
|             string oldAssetPath = _settings.DefaultPrefabObjectsPath;
 | |
|             string newAssetPath = EditorGUILayout.DelayedTextField(ObjectNames.NicifyVariableName(nameof(_settings.DefaultPrefabObjectsPath)), oldAssetPath);
 | |
| 
 | |
|             if (GUILayout.Button(_folderIcon, iconWidthConstraint, iconHeightConstraint))
 | |
|             {
 | |
|                 if (TrySaveFilePathInsideAssetsFolder(null, Application.dataPath, "DefaultPrefabObjects", "asset", out string result))
 | |
|                     newAssetPath = result;
 | |
|                 else
 | |
|                     EditorWindow.focusedWindow.ShowNotification(new GUIContent($"{ObjectNames.NicifyVariableName(nameof(_settings.DefaultPrefabObjectsPath))} must be inside the Assets folder."));
 | |
|             }
 | |
| 
 | |
|             if (!newAssetPath.Equals(oldAssetPath, StringComparison.OrdinalIgnoreCase))
 | |
|             {
 | |
|                 if (newAssetPath.StartsWith($"Assets{Path.DirectorySeparatorChar}", StringComparison.OrdinalIgnoreCase))
 | |
|                 {
 | |
|                     if (File.Exists(newAssetPath))
 | |
|                     {
 | |
|                         EditorWindow.focusedWindow.ShowNotification(new GUIContent("Another asset already exists at the new path."));
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         Generator.IgnorePostProcess = true;
 | |
| 
 | |
|                         if (File.Exists(oldAssetPath))
 | |
|                             AssetDatabase.MoveAsset(oldAssetPath, newAssetPath);
 | |
|                         _settings.DefaultPrefabObjectsPath = newAssetPath;
 | |
| 
 | |
|                         Generator.IgnorePostProcess = false;
 | |
|                     }
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     EditorWindow.focusedWindow.ShowNotification(new GUIContent($"{ObjectNames.NicifyVariableName(nameof(_settings.DefaultPrefabObjectsPath))} must be inside the Assets folder."));
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             EditorGUILayout.EndHorizontal();
 | |
| 
 | |
|             int currentSearchScope = _settings.SearchScope;
 | |
|             SearchScopeType searchScopeType = (SearchScopeType)EditorGUILayout.EnumPopup(ValueToSearchScope(_settings.SearchScope));
 | |
|             _settings.SearchScope = (int)searchScopeType;
 | |
|             SearchScopeType ValueToSearchScope(int value) => (SearchScopeType)value;
 | |
|             if (_settings.SearchScope == (int)SearchScopeType.EntireProject)
 | |
|             {
 | |
|                 EditorGUILayout.HelpBox("Searching the entire project for prefabs can become very slow. Consider switching the search scope to specific folders instead.", MessageType.Warning);
 | |
| 
 | |
|                 if (GUILayout.Button("Switch"))
 | |
|                     _settings.SearchScope = (int)SearchScopeType.SpecificFolders;
 | |
|             }
 | |
|             //If search scope changed then update prefabs.
 | |
|             if (currentSearchScope != _settings.SearchScope && (SearchScopeType)_settings.SearchScope == SearchScopeType.EntireProject)
 | |
|                 Generator.GenerateFull();
 | |
| 
 | |
|             List<string> folders = null;
 | |
|             string foldersName = null;
 | |
| 
 | |
|             if (_settings.SearchScope == (int)SearchScopeType.EntireProject)
 | |
|             {
 | |
|                 folders = _settings.ExcludedFolders;
 | |
|                 foldersName = ObjectNames.NicifyVariableName(nameof(_settings.ExcludedFolders));
 | |
|             }
 | |
|             else if (_settings.SearchScope == (int)SearchScopeType.SpecificFolders)
 | |
|             {
 | |
|                 folders = _settings.IncludedFolders;
 | |
|                 foldersName = ObjectNames.NicifyVariableName(nameof(_settings.IncludedFolders));
 | |
|             }
 | |
| 
 | |
|             string folderName = foldersName.Substring(0, foldersName.Length - 1);
 | |
| 
 | |
|             if ((_showFolders = EditorGUILayout.Foldout(_showFolders, $"{foldersName} ({folders.Count})")) && folders != null)
 | |
|             {
 | |
|                 EditorGUI.indentLevel++;
 | |
| 
 | |
|                 for (int i = 0; i < folders.Count; i++)
 | |
|                 {
 | |
|                     EditorGUILayout.BeginHorizontal();
 | |
| 
 | |
|                     string oldFolder = folders[i];
 | |
|                     string newFolder = SlashRegex.Replace(EditorGUILayout.DelayedTextField(oldFolder), Path.DirectorySeparatorChar.ToString());
 | |
|                     if (!newFolder.Equals(oldFolder, StringComparison.OrdinalIgnoreCase))
 | |
|                     {
 | |
|                         if (newFolder.StartsWith($"Assets{Path.DirectorySeparatorChar}", StringComparison.OrdinalIgnoreCase))
 | |
|                             folders[i] = newFolder;
 | |
|                         else
 | |
|                             EditorWindow.focusedWindow.ShowNotification(new GUIContent($"{folderName} must be inside the Assets folder."));
 | |
|                     }
 | |
| 
 | |
|                     if (GUILayout.Button(_folderIcon, iconWidthConstraint, iconHeightConstraint))
 | |
|                     {
 | |
|                         if (TryOpenFolderPathInsideAssetsFolder(null, Application.dataPath, null, out string result))
 | |
|                             folders[i] = result;
 | |
|                         else
 | |
|                             EditorWindow.focusedWindow.ShowNotification(new GUIContent($"{folderName} must be inside the Assets folder."));
 | |
|                     }
 | |
| 
 | |
|                     if (GUILayout.Button(_deleteIcon, iconWidthConstraint, iconHeightConstraint)) folders.RemoveAt(i);
 | |
| 
 | |
|                     EditorGUILayout.EndHorizontal();
 | |
|                 }
 | |
| 
 | |
|                 EditorGUI.indentLevel--;
 | |
| 
 | |
|                 if (_settings.SearchScope == (int)SearchScopeType.SpecificFolders) EditorGUILayout.HelpBox("You can include subfolders by appending an asterisk (*) to a path.", MessageType.None);
 | |
| 
 | |
|                 if (GUILayout.Button("Browse"))
 | |
|                 {
 | |
|                     if (TryOpenFolderPathInsideAssetsFolder(null, Application.dataPath, null, out string result))
 | |
|                     {
 | |
|                         folders.Add(result);
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         EditorWindow.focusedWindow.ShowNotification(new GUIContent($"{folderName} must be inside the Assets folder."));
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             if (EditorGUI.EndChangeCheck())
 | |
|                 Configuration.Configurations.Write(true);
 | |
|             if (GUILayout.Button("Generate"))
 | |
|                 Generator.GenerateFull();
 | |
| 
 | |
|             EditorGUILayout.HelpBox("Consider pressing 'Generate' after changing the settings.", MessageType.Info);
 | |
| 
 | |
|             EditorGUILayout.EndScrollView();
 | |
|         }
 | |
| 
 | |
|         private static bool TrySaveFilePathInsideAssetsFolder(string title, string directory, string name, string extension, out string result)
 | |
|         {
 | |
|             result = null;
 | |
| 
 | |
|             string selectedPath = EditorUtility.SaveFilePanel(title, directory, name, extension);
 | |
| 
 | |
|             if (selectedPath.StartsWith(Application.dataPath, StringComparison.OrdinalIgnoreCase))
 | |
|             {
 | |
|                 result = SlashRegex.Replace(selectedPath.Remove(0, Path.GetDirectoryName(Application.dataPath).Length + 1), Path.DirectorySeparatorChar.ToString());
 | |
| 
 | |
|                 return true;
 | |
|             }
 | |
| 
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
|         private static bool TryOpenFolderPathInsideAssetsFolder(string title, string folder, string name, out string result)
 | |
|         {
 | |
|             result = null;
 | |
| 
 | |
|             string selectedPath = EditorUtility.OpenFolderPanel(title, folder, name);
 | |
| 
 | |
|             if (selectedPath.StartsWith(Application.dataPath, StringComparison.OrdinalIgnoreCase))
 | |
|             {
 | |
|                 result = SlashRegex.Replace(selectedPath.Remove(0, Path.GetDirectoryName(Application.dataPath).Length + 1), Path.DirectorySeparatorChar.ToString());
 | |
| 
 | |
|                 return true;
 | |
|             }
 | |
| 
 | |
|             return false;
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| #endif |