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
}
}