using UnityEditor; using UnityEngine; // Sci-Fi Ship Controller. Copyright (c) 2018-2022 SCSM Pty Ltd. All rights reserved. namespace SciFiShipController { // Script that performs miscellaneous setup tasks for Sci-Fi Ship Controller - runs when the project is opened in the Unity editor // See also SSCDemoSetup [InitializeOnLoad] public static class SSCSetup { #region Public Static Variables public static string sscFolder = "Assets/SCSM/SciFiShipController"; public static string materialsFolder = "Assets/SCSM/SciFiShipController/Materials"; public static string texturesFolder = "Assets/SCSM/SciFiShipController/Textures"; public static string modelsFolder = "Assets/SCSM/SciFiShipController/Models"; public static string effectsFolder = "Assets/SCSM/SciFiShipController/Prefabs/Effects"; public static string destructFolder = "Assets/SCSM/SciFiShipController/Prefabs/Destructs"; public static string projectilesFolder = "Assets/SCSM/SciFiShipController/Prefabs/Projectiles"; public static string beamsFolder = "Assets/SCSM/SciFiShipController/Prefabs/Beams"; public static string demoMaterialsFolder = "Assets/SCSM/SciFiShipController/Demos/Materials"; public static string demoModelsFolder = "Assets/SCSM/SciFiShipController/Demos/Models"; public static string demoScriptsFolder = "Assets/SCSM/SciFiShipController/Demos/Scripts"; #endregion #region Public Structures public struct PackageCustomInfo { public string version; } #endregion #region Private Static variables private static SerializedObject tagManager; #endregion #region Constructor static SSCSetup() { // See SSCDemoSetup for adding the SSC Celestials layer. // This was moved into SSCDemoSetup for the scenario when the Demo folder is not imported. //int[] layerNumbersToAdd = { Celestials.celestialsUnityLayer }; //string[] layersToAdd = { "SSC Celestials" }; FindTagAndLayerManager(); //CreateLayers(layersToAdd, layerNumbersToAdd); DefineSymbols(); UpgradeProject(); } #endregion #region Private Static Methods /// /// Add the define for SSC so devs can use the following define in their scripts to call SSC methods /// #if SCSM_SSC /// // Call SSC APIs /// #endif /// private static void DefineSymbols() { const string SSC_Define = "SCSM_SSC"; const string SSC_Rewired_Define = "SSC_REWIRED"; const string SSC_OVR_Define = "SSC_OVR"; // Oculus VR const string SCSM_XR_Define = "SCSM_XR"; System.Type reInputType = null; System.Type ovrInputType = null; System.Type xrDeviceType = null; string defines = PlayerSettings.GetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup); #region SSC if (!defines.Contains(SSC_Define)) { if (string.IsNullOrEmpty(defines)) { defines = SSC_Define; } else if (!defines.EndsWith(";")) { defines += ";" + SSC_Define; } PlayerSettings.SetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup, defines); } #endregion #region Rewired // Rewired currently does not have a global define. If it is installed, add one, else remove it if it already exists try { //Debug.Log("type: " + typeof(Rewired.ReInput).AssemblyQualifiedName); reInputType = System.Type.GetType("Rewired.ReInput, Rewired_Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", true, true); if (reInputType != null && !defines.Contains(SSC_Rewired_Define)) { if (string.IsNullOrEmpty(defines)) { defines = SSC_Rewired_Define; } else if (!defines.EndsWith(";")) { defines += ";" + SSC_Rewired_Define; } PlayerSettings.SetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup, defines); } } catch { //Debug.LogWarning("SSCSetup.DefineSymbols: it appears that Rewired is not installed in this project."); } #endregion #region Oculus API //Debug.Log("OVR: " + typeof(OVRInput).AssemblyQualifiedName); // There are currently 2 known Oculus API versions. // Assembly-CSharp, Version=1.0.0.0 // Oculus.VR, Version=0.0.0.0 try { ovrInputType = System.Type.GetType("OVRinput, Assembly-CSharp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", true, true); if (ovrInputType != null && !defines.Contains(SSC_OVR_Define)) { if (string.IsNullOrEmpty(defines)) { defines = SSC_OVR_Define; } else if (!defines.EndsWith(";")) { defines += ";" + SSC_OVR_Define; } PlayerSettings.SetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup, defines); } } catch { } try { if (ovrInputType == null) { ovrInputType = System.Type.GetType("OVRinput, Oculus.VR, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", true, true); if (ovrInputType != null && !defines.Contains(SSC_OVR_Define)) { if (string.IsNullOrEmpty(defines)) { defines = SSC_OVR_Define; } else if (!defines.EndsWith(";")) { defines += ";" + SSC_OVR_Define; } PlayerSettings.SetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup, defines); } } } catch { } #endregion // Rewired is not installed, but there is a SSC-created global define, so remove it // NOTE: Unfortunately this doesn't work because now the PlayerInputModuleEditor won't compile if (reInputType == null && defines.Contains(SSC_Rewired_Define)) { defines = defines.Replace(";" + SSC_Rewired_Define, ""); defines = defines.Replace(SSC_Rewired_Define + ";", ""); defines = defines.Replace(SSC_Rewired_Define, ""); PlayerSettings.SetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup, defines); } #region New (Unity) Input System // This requires U2019.1, scripting runtime version .NET 4.x Equivalent, and the Package for Input System 1.0+ // For 2019.2+ could use pInfo = UnityEditor.PackageManager.PackageInfo.FindForAssetPath("Packages/com.unity.inputsystem/package.json"); // and pInfo.version #if UNITY_2019_1_OR_NEWER const string SSC_UnityInputSystem_Define = "SSC_UIS"; string uisPackageVersion = GetPackageVersion("Packages/com.unity.inputsystem/package.json"); // If the package exists, add the define if it is missing if (!string.IsNullOrEmpty(uisPackageVersion)) { if (!defines.Contains(SSC_UnityInputSystem_Define)) { if (string.IsNullOrEmpty(defines)) { defines = SSC_UnityInputSystem_Define; } else if (!defines.EndsWith(";")) { defines += ";" + SSC_UnityInputSystem_Define; } PlayerSettings.SetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup, defines); } } #endif #endregion #region Unity XR (new AR/VR system) try { xrDeviceType = System.Type.GetType("UnityEngine.XR.XRDevice, UnityEngine.VRModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", true, true); if (xrDeviceType != null && !defines.Contains(SCSM_XR_Define)) { if (string.IsNullOrEmpty(defines)) { defines = SCSM_XR_Define; } else if (!defines.EndsWith(";")) { defines += ";" + SCSM_XR_Define; } // SCSM is only going to support 2020.3+ although some providers may work in 2019.4 too. #if UNITY_2020_3_OR_NEWER PlayerSettings.SetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup, defines); #endif } } catch { } #endregion #region Entities U2019.1 or newer #if UNITY_2019_1_OR_NEWER // Due to changes in Entities, this requires Unity 2019.1 or newer const string SSC_Entity_Define = "SSC_ENTITIES"; string entitiesPackageVersion = GetPackageVersion("Packages/com.unity.entities/package.json"); string hybridRdrPackageVersion = GetPackageVersion("Packages/com.unity.rendering.hybrid/package.json"); // If editor scripts exist, add the Editor define if it is missing if (!string.IsNullOrEmpty(entitiesPackageVersion) && !string.IsNullOrEmpty(hybridRdrPackageVersion)) { // Debug.Log("[DEBUG] entities: " + entitiesPackageVersion + " hybrid renderer: " + hybridRdrPackageVersion); if (!defines.Contains(SSC_Entity_Define)) { if (string.IsNullOrEmpty(defines)) { defines = SSC_Entity_Define; } else if (!defines.EndsWith(";")) { defines += ";" + SSC_Entity_Define; } PlayerSettings.SetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup, defines); } } #endif #endregion #region Unity.Physics U2019.3 or newer #if UNITY_2019_3_OR_NEWER const string SSC_Physics_Define = "SSC_PHYSICS"; string physicsPackageVersion = GetPackageVersion("Packages/com.unity.physics/package.json"); // If the package exists, add the define if it is missing (currently only support v0.2.4. // Version 0.5.1-preview.32 needs an upgrade from IJobForEach to IJobEntity. See ProjectileSystem.cs if (!string.IsNullOrEmpty(physicsPackageVersion) && SSCUtils.CompareVersionNumbers(physicsPackageVersion, "0.2.5") < 0) { if (!defines.Contains(SSC_Physics_Define)) { if (string.IsNullOrEmpty(defines)) { defines = SSC_Physics_Define; } else if (!defines.EndsWith(";")) { defines += ";" + SSC_Physics_Define; } PlayerSettings.SetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup, defines); } } #endif #endregion #region URP 7.3.1 or newer #if UNITY_2019_3_OR_NEWER // URP 7.3.1+ with U2019.4+ supports stacked cameras which is used in Celestials. const string SSC_URP73_Define = "SSC_URP"; string urpPackageVersion = GetPackageVersion("Packages/com.unity.render-pipelines.universal/package.json"); if (!string.IsNullOrEmpty(urpPackageVersion)) { if (!defines.Contains(SSC_URP73_Define) && SSCUtils.CompareVersionNumbers(urpPackageVersion, "7.3.1") >= 0) { if (string.IsNullOrEmpty(defines)) { defines = SSC_URP73_Define; } else if (!defines.EndsWith(";")) { defines += ";" + SSC_URP73_Define; } PlayerSettings.SetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup, defines); } } #endif #endregion #region HDRP 7.3.1 or newer #if UNITY_2019_3_OR_NEWER // HDRP 7.3.1+ support with U2019.4 is used in Celestials. const string SSC_HDRP73_Define = "SSC_HDRP"; string hdrpPackageVersion = GetPackageVersion("Packages/com.unity.render-pipelines.high-definition/package.json"); if (!string.IsNullOrEmpty(hdrpPackageVersion)) { if (!defines.Contains(SSC_HDRP73_Define) && SSCUtils.CompareVersionNumbers(hdrpPackageVersion, "7.3.1") >= 0) { if (string.IsNullOrEmpty(defines)) { defines = SSC_HDRP73_Define; } else if (!defines.EndsWith(";")) { defines += ";" + SSC_HDRP73_Define; } PlayerSettings.SetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup, defines); } } #endif #endregion } // Upgrade project folders and move anything to correct location private static void UpgradeProject() { // Move stars into Environment folder MoveAsset("SSCSetup.UpgradeProject", demoModelsFolder, demoModelsFolder + "/Environment", "StarLowPolyFBX.fbx"); // Move demo models from main models folder to demos MoveAsset("SSCSetup.UpgradeProject", modelsFolder + "/Environment", demoModelsFolder + "/Environment", "AGTrack1.fbx"); MoveAsset("SSCSetup.UpgradeProject", modelsFolder + "/Environment", demoModelsFolder + "/Environment", "FlatCityscape1.fbx"); MoveAsset("SSCSetup.UpgradeProject", modelsFolder + "/Environment", demoModelsFolder + "/Environment", "RingCityscape1.fbx"); MoveAsset("SSCSetup.UpgradeProject", modelsFolder + "/Environment", demoModelsFolder + "/Environment", "SpaceRingsTrack1.fbx"); // Move stars material into Environment folder MoveAsset("SSCSetup.UpgradeProject", demoMaterialsFolder, demoMaterialsFolder + "/Environment", "LBStar.mat"); // Move demo materials from main materials folder to demos MoveAsset("SSCSetup.UpgradeProject", materialsFolder + "/Environment", demoMaterialsFolder + "/Environment", "SCSM_Building_Wall_1.mat"); MoveAsset("SSCSetup.UpgradeProject", materialsFolder + "/Environment", demoMaterialsFolder + "/Environment", "SCSM_Building_Wall_2.mat"); MoveAsset("SSCSetup.UpgradeProject", materialsFolder + "/Environment", demoMaterialsFolder + "/Environment", "SCSM_Building_Window.mat"); MoveAsset("SSCSetup.UpgradeProject", materialsFolder + "/Environment", demoMaterialsFolder + "/Environment", "SCSM_Floating_City_Base.mat"); MoveAsset("SSCSetup.UpgradeProject", materialsFolder + "/Environment", demoMaterialsFolder + "/Environment", "SCSM_Ground_sand.mat"); MoveAsset("SSCSetup.UpgradeProject", materialsFolder + "/Environment", demoMaterialsFolder + "/Environment", "SCSM_Metal_Tech.mat"); MoveAsset("SSCSetup.UpgradeProject", materialsFolder + "/Environment", demoMaterialsFolder + "/Environment", "SCSM_Sign_Colour_1.mat"); MoveAsset("SSCSetup.UpgradeProject", materialsFolder + "/Environment", demoMaterialsFolder + "/Environment", "SCSM_Sign_Colour_2.mat"); MoveAsset("SSCSetup.UpgradeProject", materialsFolder + "/Environment", demoMaterialsFolder + "/Environment", "SCSM_Sign_Post.mat"); MoveAsset("SSCSetup.UpgradeProject", materialsFolder + "/Environment", demoMaterialsFolder + "/Environment", "SCSM_SSC_Skybox.mat"); MoveAsset("SSCSetup.UpgradeProject", materialsFolder + "/Environment", demoMaterialsFolder + "/Environment", "SCSM_Track_Blue.mat"); MoveAsset("SSCSetup.UpgradeProject", materialsFolder + "/Environment", demoMaterialsFolder + "/Environment", "SCSM_Track_Glass_Barrier.mat"); MoveAsset("SSCSetup.UpgradeProject", materialsFolder + "/Environment", demoMaterialsFolder + "/Environment", "SCSM_Track_Grey.mat"); MoveAsset("SSCSetup.UpgradeProject", materialsFolder + "/Environment", demoMaterialsFolder + "/Environment", "SCSM_Track_Orange.mat"); DeleteAsset(demoScriptsFolder + "/EndlessFlierDemoScript.cs"); RenameAsset("SSCSetup.UpgradeProject", sscFolder + "/SRP", "SSC_HDRP.unitypackage", "SSC_HDRP_5.13.0.unitypackage"); } #endregion #region Public Static Methods public static void FindTagAndLayerManager() { tagManager = new SerializedObject(AssetDatabase.LoadAllAssetsAtPath("ProjectSettings/TagManager.asset")[0]); } /// /// Create a new Unity Layer. Optionally overwrite existing layer if one already exists. /// /// /// /// /// public static void CreateLayers(string[] newLayers, int[] newlayerNumbers, bool overwriteExisting = false) { if (tagManager != null) { // Get the array of existing layers SerializedProperty layers = tagManager.FindProperty("layers"); if (layers != null) { if (layers.isArray) { for (int l = 0; l < newlayerNumbers.Length; l++) { SerializedProperty layerSP = layers.GetArrayElementAtIndex(newlayerNumbers[l]); if ((overwriteExisting || string.IsNullOrEmpty(layerSP.stringValue)) && layerSP.stringValue != newLayers[l]) { Debug.Log("Adding layer " + newlayerNumbers[l].ToString() + ": " + newLayers[l]); layerSP.stringValue = newLayers[l]; } } // Apply the modifications tagManager.ApplyModifiedProperties(); } else { Debug.LogWarning("Layers Serialized Property is not in the expected format (array), so layers could not be created."); } } else { Debug.LogWarning("Layers Serialized Property is null, so layers could not be created"); } } else { Debug.LogWarning("TagManager.asset could not be found, so layers could not be created."); } } /// /// Move a file from one folder to another in the Project Hierarchy /// Keep the meta-data the same so as not to break linked assets in scenes /// USAGE: SSCSetup.MoveAsset("SSCSetup.UpgradeProject", materialsFolder, materialsFolder + "/Resources", "LBMoon.mat"); /// /// /// /// /// public static void MoveAsset(string sourceMethod, string sourceFolder, string destFolder, string fileName) { string sourcePath = sourceFolder + (sourceFolder.EndsWith("/") ? "" : "/") + fileName; string destPath = destFolder + (destFolder.EndsWith("/") ? "" : "/") + fileName; //Debug.Log("[DEBUG] Source: " + sourcePath + " dest: " + destPath); if (System.IO.File.Exists(sourcePath)) { CheckFolder(destFolder); if (!AssetDatabase.IsValidFolder(destFolder)) { Debug.Log(sourceMethod + " could not move " + fileName + " because the destination folder isn't in asset database: " + destFolder); } else if (!System.IO.File.Exists(destPath)) { Debug.Log(sourceMethod + " - moving " + fileName + " from " + sourceFolder + " to " + destFolder + "..."); string status = AssetDatabase.MoveAsset(sourcePath, destPath); if (status != "") { Debug.LogWarning("SSCSetup.UpgradeProject - " + status); } else { Debug.Log(sourceMethod + " - moved " + fileName + " from " + sourceFolder + " to " + destFolder + "."); } } } } /// /// Delete a file from the Project Hierarchy /// USAGE: SSCSetup.DeleteAsset("Assets/SCSM/SciFiShipController/Demos/Scripts/myfile.cs"); /// /// public static void DeleteAsset(string filepath) { if (System.IO.File.Exists(filepath)) { AssetDatabase.DeleteAsset(filepath); } } /// /// Rename a file if it exists and the new file does not exist /// USAGE: SSCSetup.RenameAsset("SSCSetup.UpgradeProject", "Assets/SciFiShipController/SRP", "SSC_HDRP.unitypackage", "SSC_HDRP_5.13.0.unitypackage"); /// /// /// /// /// public static void RenameAsset(string sourceMethod, string filePath, string oldFileName, string newFilename) { if (!System.IO.File.Exists(filePath + "/" + newFilename) && System.IO.File.Exists(filePath + "/" + oldFileName)) { string status = AssetDatabase.RenameAsset(filePath + "/" + oldFileName, newFilename); if (status != "") { Debug.LogWarning(sourceMethod + " - " + status); } else { Debug.Log(sourceMethod + " - renamed " + filePath + "/" + oldFileName + " to " + newFilename); } } } // Check folder is valid. If it is missing, create it. // Does not check for multiple folder levels. Just the last one public static void CheckFolder(string folderPath) { // CreateFolder doesn't work immediately. This can result it it seeming to be invalid immediately after calling CreateFolder. // Check the filesystem too, so that we don't create multiple folders with a the next sequential number appended to the folder name. if (!AssetDatabase.IsValidFolder(folderPath) && !System.IO.Directory.Exists(folderPath)) { int i = folderPath.LastIndexOf('/'); if (i >= 0 && i < folderPath.Length - 2) { Debug.Log("INFO SSCSetup - Creating new folder " + folderPath.Substring(i + 1) + " in " + folderPath.Substring(0, i)); // NOTE: This doesn't have an immediate effect. SaveAssets() and Refresh() have no effect. AssetDatabase.CreateFolder(folderPath.Substring(0, i), folderPath.Substring(i + 1)); } } } /// /// Get the version number for a package. Typically the package can be found in the "Packages" /// virtual folder. Will return an empty string if the package does not exist in the project. /// USAGE: string packageVersion = GetPackageVersion("Packages/com.unity.inputsystem/package.json"); /// /// public static string GetPackageVersion(string packagePath) { #if UNITY_2019_2_OR_NEWER UnityEditor.PackageManager.PackageInfo pInfo = UnityEditor.PackageManager.PackageInfo.FindForAssetPath(packagePath); if (pInfo != null) { return pInfo.version; } else { return string.Empty; } #else if (System.IO.File.Exists(packagePath)) { string packageJSON = System.IO.File.ReadAllText(packagePath); if (!string.IsNullOrEmpty(packageJSON)) { PackageCustomInfo info = JsonUtility.FromJson(packageJSON); return info.version; } else { return string.Empty; } } else { return string.Empty;} #endif } #endregion } }