Exemple #1
0
 public static void DeleteAllProjectSettings()
 {
     foreach (var plugin in PluginContainer.plugins)
     {
         AssetDatabase.DeleteAsset(PathUtility.FromProject(plugin.configuration.projectSettingsStoragePath));
     }
 }
Exemple #2
0
        public static bool TryLoad <T>(string path, out T asset) where T : ScriptableObject
        {
            var assetDatabasePath = PathUtility.FromProject(path);

            if (File.Exists(path))
            {
                // Try loading the existing asset file.
                asset = AssetDatabase.LoadAssetAtPath <T>(assetDatabasePath);

                if (asset == null)
                {
                    // The file exists, but it isn't a valid asset.
                    // Warn and leave the asset as is to prevent losing its serialized contents
                    // because we might be able to salvage them by deserializing later on.
                    // Return a new empty instance in the mean time.
                    Debug.LogWarning($"Loading {typeof(T).FullName} failed:\n{assetDatabasePath}");
                    asset = ScriptableObject.CreateInstance <T>();
                    return(false);
                }
            }
            else
            {
                // The file doesn't exist, so create a new asset and save it.
                asset = ScriptableObject.CreateInstance <T>();
                PathUtility.CreateParentDirectoryIfNeeded(path);
                AssetDatabase.CreateAsset(asset, assetDatabasePath);
                AssetDatabase.SaveAssets();
            }

            return(true);
        }
        public T LoadAsset <T>(string path) where T : UnityObject
        {
            Ensure.That(nameof(path)).IsNotNull(path);

            path = PathUtility.FromProject(NormalizePath(path));

            return((T)AssetDatabase.LoadAssetAtPath <T>(path));
        }
Exemple #4
0
        public static void Run()
        {
            var pluginImporters = PluginImporter.GetAllImporters();

            foreach (var pluginImporter in pluginImporters)
            {
                // Skip native plugins
                if (pluginImporter.isNativePlugin)
                {
                    continue;
                }

                // Skip built-in Unity plugins, which are referenced by full path
                if (!pluginImporter.assetPath.StartsWith("Assets"))
                {
                    continue;
                }

                var assemblyPath = Path.Combine(Directory.GetParent(Application.dataPath).FullName, pluginImporter.assetPath);

                var assembly = Codebase.assemblies.FirstOrDefault(a => !string.IsNullOrEmpty(a.Location) && new Uri(assemblyPath) == new Uri(a.Location));

                // Skip if plugin importer has no matching assembly
                if (assembly == null)
                {
                    continue;
                }

                var plugin = PluginContainer.plugins.FirstOrDefault(p => p.runtimeAssembly == assembly);

                // Skip if the assembly is not mapped to a Ludiq plugin
                if (plugin == null)
                {
                    continue;
                }

                var mappableTypes = assembly.GetTypesSafely().Where(t => typeof(UnityObject).IsAssignableFrom(t));

                // Skip assemblies without any mappable types
                if (!mappableTypes.Any())
                {
                    continue;
                }

                // Create a dictionary of type-to-icon mapping
                // The key is the fully qualified type name.
                // The value is the Unity-assigned GUID of the icon file.
                var iconsByTypes = new Dictionary <string, string>();

                foreach (var type in mappableTypes)
                {
                    var iconAssetPath = PathUtility.FromProject(Path.Combine(plugin.paths.iconMap, type.CSharpFileName(true, false) + ".png"));

                    var typeIcon = AssetDatabase.LoadAssetAtPath <Texture2D>(iconAssetPath);

                    // Skip if type icon loading fails
                    if (typeIcon == null)
                    {
                        continue;
                    }

                    iconsByTypes.Add(type.ToString(), AssetDatabase.AssetPathToGUID(iconAssetPath));
                }

                // Modify the matching meta file's YAML
                var metaFilePath = assemblyPath + ".meta";

                try
                {
                    var yaml = new YamlStream();

                    new FileInfo(metaFilePath).IsReadOnly = false;

                    using (var input = new StreamReader(metaFilePath))
                    {
                        yaml.Load(input);

                        // Dig down the PluginImporter.iconMap node and clear it
                        var rootNode           = (YamlMappingNode)yaml.Documents[0].RootNode;
                        var pluginImporterNode = (YamlMappingNode)rootNode.Children["PluginImporter"];
                        var iconMapNode        = (YamlMappingNode)pluginImporterNode.Children["iconMap"];

                        iconMapNode.Children.Clear();

                        AddIconMap(iconMapNode, iconsByTypes);

                        iconMapNode.Style = MappingStyle.Block;
                    }

                    // The only way I found to get Unity to release its freaking file lock
                    File.Delete(metaFilePath);

                    using (var output = new StreamWriter(metaFilePath))
                    {
                        yaml.Save(output, false);
                    }

                    Debug.Log($"Added icon mapping.\n{metaFilePath}");
                }
                catch (Exception ex)
                {
                    Debug.LogWarning($"Failed to traverse plugin meta file '{Path.GetFileName(metaFilePath)}' for icon mapping: \n{ex}");

                    if (iconsByTypes.Count > 0)
                    {
                        // Unity broke Yaml specification in 5.5: (... ugh)
                        // https://fogbugz.unity3d.com/default.asp?909364_td7ssft6c2cgh3i2
                        // YamlDotNet won't be able to load the meta files.
                        // Therefore, we'll have to add the iconmap manually in the meta files.
                        // To facilitate that process, we'll output the proper required Yaml
                        // to the console for each file.

                        var iconMapNode = new YamlMappingNode();
                        AddIconMap(iconMapNode, iconsByTypes);
                        iconMapNode.Style = MappingStyle.Block;
                        var rootNode = new YamlMappingNode {
                            { "iconMap", iconMapNode }
                        };
                        var yaml   = new YamlStream(new YamlDocument(rootNode));
                        var output = new StringWriter();
                        yaml.Save(output, false);
                        output.Dispose();
                        var @string  = output.ToString();
                        var indented = "";
                        foreach (var line in @string.Split('\n'))
                        {
                            indented += "  " + line + "\n";
                        }
                        Debug.Log($"Manual iconMap node for '{Path.GetFileName(metaFilePath)}':\n\n{indented}\n\n");
                    }
                }
            }

            AssetDatabase.Refresh();

            AnnotationDisabler.DisableGizmos();
        }
Exemple #5
0
        // Perforce and other VCS have a lock mechanism that usually
        // only makes the file writable once checked out. We need to
        // check them out before writing to them for auto-generated files.
        public static void Unlock(string path)
        {
            Ensure.That(nameof(path)).IsNotNull(path);

            UnityAPI.Await
            (
                () =>
            {
                // The API changed in 2019, adding a third optional ChangeSet parameter
                // which defaults to null but breaks the compiled signature below
                // Furthermore, we can't even so much as have the call in the body of this method,
                // or it will fail even if the if branch evaluates to false. So we

                if (File.Exists(path) && Provider.enabled && Provider.isActive && Provider.hasCheckoutSupport)
                {
                    try
                    {
                        var provider = typeof(Provider);

                        if (EditorApplicationUtility.unityVersion >= "2019.1.0")
                        {
                            var method = provider.GetMethods()
                                         .FirstOrDefault
                                         (
                                m => m.Name == "Checkout" &&
                                m.GetParameters().Length == 3 &&
                                m.GetParameters()[0].ParameterType == typeof(string) &&
                                m.GetParameters()[1].ParameterType == typeof(CheckoutMode)
                                         );

                            if (method == null)
                            {
                                throw new MissingMemberException(provider.FullName, "Checkout");
                            }

                            method.InvokeOptimized(null, PathUtility.FromProject(path), CheckoutMode.Both, null);
                        }
                        else
                        {
                            var method = provider.GetMethods()
                                         .FirstOrDefault
                                         (
                                m => m.Name == "Checkout" &&
                                m.GetParameters().Length == 2 &&
                                m.GetParameters()[0].ParameterType == typeof(string) &&
                                m.GetParameters()[1].ParameterType == typeof(CheckoutMode)
                                         );

                            if (method == null)
                            {
                                throw new MissingMemberException(provider.FullName, "Checkout");
                            }

                            method.InvokeOptimized(null, PathUtility.FromProject(path), CheckoutMode.Both);
                        }
                    }
                    catch (Exception ex)
                    {
                        Debug.LogWarning($"Failed to automatically checkout file from version control:\n{path}\n{ex}");
                    }
                }

                if (File.Exists(path))
                {
                    var info = new FileInfo(path);

                    if (info.IsReadOnly)
                    {
                        var sb = new StringBuilder();
                        sb.AppendLine($"File '{info.Name}' is read-only despite attempted checkout. Manually forcing to writable.");
                        sb.AppendLine($"This may cause version control issues. Please report the following debug information:");
                        sb.AppendLine($"File Exists: {File.Exists(path)}");
                        sb.AppendLine($"Provider.enabled: {Provider.enabled}");
                        sb.AppendLine($"Provider.isActive: {Provider.isActive}");
                        sb.AppendLine($"Provider.hasCheckoutSupport: {Provider.hasCheckoutSupport}");
                        Debug.LogWarning(sb.ToString());

                        info.IsReadOnly = false;
                    }
                }
            }
            );
        }
        protected override void OnContentGUI()
        {
            GUILayout.BeginVertical(Styles.background, GUILayout.ExpandHeight(true));

            var label = "Every Unity build target except Standalone requires 'ahead of time' (AOT) compilation. ";

            label += "Before building for these platforms, you should always run this step to create AOT stubs for reflection and generics. ";
            label += "Otherwise, there may be runtime errors in your builds.";

            var label2 = "This pre-build step will scan all the assets and scenes in the project to generate the required AOT stubs. ";

            label2 += "Make sure you save the current scene before starting.";

            LudiqGUI.FlexibleSpace();
            GUILayout.Label(label, LudiqStyles.centeredLabel);
            LudiqGUI.FlexibleSpace();
            GUILayout.Label(label2, LudiqStyles.centeredLabel);
            LudiqGUI.FlexibleSpace();

            LudiqGUI.BeginHorizontal();
            LudiqGUI.FlexibleSpace();

            if (GUILayout.Button("Pre-Build", Styles.nextButton))
            {
                try
                {
                    AotPreBuilder.GenerateLinker();
                    AotPreBuilder.GenerateStubScript();
                    EditorUtility.DisplayDialog("AOT Pre-Build", $"AOT pre-build has completed.\n\nThe generated linker file is located at:\n'{PathUtility.FromProject(AotPreBuilder.aotStubsPath)}'\n\nThe generated stubs script is located at:\n'{PathUtility.FromProject(AotPreBuilder.linkerPath)}'", "OK");
                    Complete();
                }
                catch (Exception ex)
                {
                    EditorUtility.DisplayDialog("AOT Pre-Build Error", $"AOT pre-build has failed: \n{ex.Message}", "OK");
                    Debug.LogException(ex);
                    AotPreBuilder.DeleteLinker();
                    AotPreBuilder.DeleteStubScript();
                }
            }

            LudiqGUI.FlexibleSpace();
            LudiqGUI.EndHorizontal();

            LudiqGUI.FlexibleSpace();
            EditorGUILayout.HelpBox("AOT Pre-build is in Beta. Please report any compile-time or runtime error you may encounter.", MessageType.Warning);
            LudiqGUI.FlexibleSpace();

            LudiqGUI.EndVertical();
        }
        public static void Run(IEnumerable <string> paths, IEnumerable <ScriptReferenceReplacement> replacements, Mode mode)
        {
            if (!canRun)
            {
                var message = "Cannot run missing script resolver with the current serialization mode.\nSet the project serialization mode to 'Force Text' and try again.";

                if (mode == Mode.Dialog)
                {
                    EditorUtility.DisplayDialog("Script Reference Resolver", message, "OK");
                }
                else if (mode == Mode.Console)
                {
                    Debug.LogWarning(message);
                }

                return;
            }

            // Doing a naive approach here: replacing the exact string by regex instead of parsing the YAML,
            // since Unity sometimes breaks YAML specifications. This is whitespace dependant, but it should work.

            var newContents = new Dictionary <string, string[]>();

            var _paths    = paths.ToArray();
            var pathIndex = 0;

            foreach (var path in _paths)
            {
                if (newContents.ContainsKey(path))
                {
                    // Duplicate path
                    continue;
                }

                var replaced     = false;
                var fileContents = new List <string>();

                if (mode == Mode.Dialog)
                {
                    ProgressUtility.DisplayProgressBar("Script Reference Resolver", $"Analyzing '{path}'...", pathIndex++ / (float)_paths.Length);
                }

                foreach (var line in File.ReadAllLines(path))
                {
                    var newLine = line;

                    foreach (var replacement in replacements)
                    {
                        var previousReferenceRegex = new Regex($@"\{{fileID: {replacement.previousReference.fileID}, guid: {replacement.previousReference.guid}, type: 3\}}");

                        newLine = previousReferenceRegex.Replace(newLine, (match) =>
                        {
                            replaced = true;

                            return($@"{{fileID: {replacement.newReference.fileID}, guid: {replacement.newReference.guid}, type: 3}}");
                        });
                    }

                    fileContents.Add(newLine);
                }

                if (replaced)
                {
                    newContents.Add(path, fileContents.ToArray());
                }
            }

            pathIndex = 0;

            if (newContents.Count > 0)
            {
                var pathMaxLength = 40;
                var fileLimit     = 15;
                var fileList      = newContents.Keys.Select(p => StringUtility.PathEllipsis(PathUtility.FromProject(p), pathMaxLength)).Take(fileLimit).ToLineSeparatedString();

                if (newContents.Count > fileLimit)
                {
                    fileList += "\n...";
                }

                var replace = true;

                if (mode == Mode.Dialog)
                {
                    var message = $"Missing script references have been found in {newContents.Count} file{(newContents.Count > 1 ? "s" : "")}: \n\n{fileList}\n\nProceed with replacement?";

                    replace = EditorUtility.DisplayDialog("Script Reference Resolver", message, "Replace References", "Cancel");
                }

                if (replace)
                {
                    foreach (var newContent in newContents)
                    {
                        if (mode == Mode.Dialog)
                        {
                            ProgressUtility.DisplayProgressBar("Script Reference Resolver", $"Fixing '{newContent.Key}'...", pathIndex++ / (float)_paths.Length);
                        }

                        VersionControlUtility.Unlock(newContent.Key);
                        File.WriteAllLines(newContent.Key, newContent.Value);
                    }

                    if (mode == Mode.Dialog)
                    {
                        EditorUtility.DisplayDialog("Script Reference Resolver", "Script references have been successfully replaced.", "OK");
                    }
                    else if (mode == Mode.Console)
                    {
                        Debug.Log($"Missing script references have been replaced in {newContents.Count} file{(newContents.Count > 1 ? "s" : "")}: \n{fileList}\n");
                    }

                    AssetDatabase.Refresh(ImportAssetOptions.ForceSynchronousImport);
                }
            }
            else
            {
                var message = "No missing script reference was found.";

                if (mode == Mode.Dialog)
                {
                    EditorUtility.DisplayDialog("Script Reference Resolver", message, "OK");
                }
                else if (mode == Mode.Console)
                {
                    // Debug.Log(message);
                }
            }

            if (mode == Mode.Dialog)
            {
                ProgressUtility.ClearProgressBar();
            }
        }
Exemple #8
0
        public static string GetPluginRuntimeGUID(Plugin plugin)
        {
            Ensure.That(nameof(plugin)).IsNotNull(plugin);

            return(AssetDatabase.AssetPathToGUID(PathUtility.FromProject(plugin.runtimeAssembly.Location)));
        }