cvr-props/Assets/ABI.CCK/Scripts/Editor/CCK_BuildUtility.cs

417 lines
17 KiB
C#
Raw Normal View History

2023-01-22 16:38:23 +01:00
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
2023-07-30 01:20:46 +02:00
using System.Threading.Tasks;
2023-01-22 16:38:23 +01:00
using ABI.CCK.Components;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
using UnityEngine.XR;
using Object = UnityEngine.Object;
2023-07-30 01:20:46 +02:00
using Random = System.Random;
2023-01-22 16:38:23 +01:00
namespace ABI.CCK.Scripts.Editor
{
public class CCK_BuildUtility
{
#region Variables
2023-01-22 16:38:23 +01:00
public static PreAvatarBundleEvent PreAvatarBundleEvent = new PreAvatarBundleEvent();
public static PrePropBundleEvent PrePropBundleEvent = new PrePropBundleEvent();
public static PreWorldBundleEvent PreWorldBundleEvent = new PreWorldBundleEvent();
2023-07-30 01:20:46 +02:00
public static string upload_id = "";
#endregion
2023-01-22 16:38:23 +01:00
#region Avatar Upload
2023-07-30 01:20:46 +02:00
public static async Task BuildAndUploadAvatar(GameObject avatarObject)
2023-01-22 16:38:23 +01:00
{
ClearLog();
EnforceVRSetting();
2023-01-22 16:38:23 +01:00
CVRAssetInfo assetInfo = avatarObject.GetComponent<CVRAssetInfo>();
2023-07-30 01:20:46 +02:00
await InitializeAPIAndSetObjectId(assetInfo, "cck/generate/avatar");
SetAssetInfoDirty(assetInfo);
GameObject instantiatedAvatar = InstantiateAndUnpackPrefab(avatarObject);
if (!HandlePreBuildEvent(PreAvatarBundleEvent.Invoke, instantiatedAvatar))
2023-07-30 01:20:46 +02:00
{
Object.DestroyImmediate(instantiatedAvatar);
return;
2023-07-30 01:20:46 +02:00
}
2023-01-22 16:38:23 +01:00
CCK_Tools.CleanEditorOnlyGameObjects(instantiatedAvatar);
2023-01-22 16:38:23 +01:00
PrefabUtility.SaveAsPrefabAsset(instantiatedAvatar,
!Application.unityVersion.Contains("2021")
? "Assets/ABI.CCK/Resources/Cache/_CVRAvatar.prefab"
: $"Assets/ABI.CCK/Resources/Cache/CVRAvatar_{assetInfo.objectId}_{assetInfo.randomNum}.prefab");
2023-01-22 16:38:23 +01:00
AssetBundleBuild assetBundleBuild = new AssetBundleBuild();
assetBundleBuild.assetNames = !Application.unityVersion.Contains("2021")
? new[] { "Assets/ABI.CCK/Resources/Cache/_CVRAvatar.prefab" }
: new[]
{
$"Assets/ABI.CCK/Resources/Cache/CVRAvatar_{assetInfo.objectId}_{assetInfo.randomNum}.prefab"
};
2023-07-30 01:20:46 +02:00
upload_id = assetInfo.objectId;
2023-07-30 01:20:46 +02:00
EditorPrefs.SetString("m_ABI_uploadId", upload_id);
EditorPrefs.SetString("m_ABI_uploadRand", assetInfo.randomNum);
2023-07-30 01:20:46 +02:00
assetBundleBuild.assetBundleName = $"cvravatar_{assetInfo.objectId}_{assetInfo.randomNum}.cvravatar";
2023-01-22 16:38:23 +01:00
BuildPipeline.BuildAssetBundles(Application.persistentDataPath, new[] {assetBundleBuild},
2023-07-30 01:20:46 +02:00
BuildAssetBundleOptions.ChunkBasedCompression, EditorUserBuildSettings.activeBuildTarget);
2023-01-22 16:38:23 +01:00
Object.DestroyImmediate(instantiatedAvatar);
if (!File.Exists($"{Application.persistentDataPath}/cvravatar_{assetInfo.objectId}_{assetInfo.randomNum}.cvravatar"))
{
Debug.LogError("Error during bundling\nThere has been an error during the bundling process. Please check your console for errors.");
EditorUtility.DisplayDialog("Error during bundling", "There has been an error during the bundling process. Please check your console for errors.", "OK");
return;
}
2023-01-22 16:38:23 +01:00
AssetDatabase.Refresh();
2023-01-22 16:38:23 +01:00
EditorPrefs.SetBool("m_ABI_isBuilding", true);
EditorApplication.isPlaying = true;
}
2023-07-30 01:20:46 +02:00
#endregion
#region Spawnable Upload
public static async Task BuildAndUploadSpawnable(GameObject spawnableObject)
{
ClearLog();
EnforceVRSetting();
2023-07-30 01:20:46 +02:00
CVRAssetInfo assetInfo = spawnableObject.GetComponent<CVRAssetInfo>();
2023-07-30 01:20:46 +02:00
CVRSpawnable spawnable = spawnableObject.GetComponent<CVRSpawnable>();
spawnable.spawnableType = CVRSpawnable.SpawnableType.StandaloneSpawnable;
EditorUtility.SetDirty(spawnable);
2023-01-22 16:38:23 +01:00
await InitializeAPIAndSetObjectId(assetInfo, "cck/generate/spawnable");
SetAssetInfoDirty(assetInfo);
2023-07-30 01:20:46 +02:00
GameObject instantiatedSpawnable = InstantiateAndUnpackPrefab(spawnableObject);
if (!HandlePreBuildEvent(PrePropBundleEvent.Invoke, instantiatedSpawnable))
2023-07-30 01:20:46 +02:00
{
Object.DestroyImmediate(instantiatedSpawnable);
return;
2023-01-22 16:38:23 +01:00
}
CCK_Tools.CleanEditorOnlyGameObjects(instantiatedSpawnable);
PrefabUtility.SaveAsPrefabAsset(instantiatedSpawnable,
!Application.unityVersion.Contains("2021")
? "Assets/ABI.CCK/Resources/Cache/_CVRSpawnable.prefab"
: $"Assets/ABI.CCK/Resources/Cache/CVRSpawnable_{assetInfo.objectId}_{assetInfo.randomNum}.prefab");
2023-01-22 16:38:23 +01:00
AssetBundleBuild assetBundleBuild = new AssetBundleBuild();
assetBundleBuild.assetNames = !Application.unityVersion.Contains("2021")
? new[] { "Assets/ABI.CCK/Resources/Cache/_CVRSpawnable.prefab" }
: new[]
{
$"Assets/ABI.CCK/Resources/Cache/CVRSpawnable_{assetInfo.objectId}_{assetInfo.randomNum}.prefab"
};
2023-07-30 01:20:46 +02:00
upload_id = assetInfo.objectId;
2023-07-30 01:20:46 +02:00
EditorPrefs.SetString("m_ABI_uploadId", upload_id);
EditorPrefs.SetString("m_ABI_uploadRand", assetInfo.randomNum);
2023-07-30 01:20:46 +02:00
assetBundleBuild.assetBundleName = $"cvrspawnable_{assetInfo.objectId}_{assetInfo.randomNum}.cvrprop";
2023-01-22 16:38:23 +01:00
BuildPipeline.BuildAssetBundles(Application.persistentDataPath, new[] {assetBundleBuild},
2023-07-30 01:20:46 +02:00
BuildAssetBundleOptions.ChunkBasedCompression, EditorUserBuildSettings.activeBuildTarget);
2023-01-22 16:38:23 +01:00
Object.DestroyImmediate(instantiatedSpawnable);
if (!File.Exists($"{Application.persistentDataPath}/cvrspawnable_{assetInfo.objectId}_{assetInfo.randomNum}.cvrprop"))
{
Debug.LogError("Error during bundling\nThere has been an error during the bundling process. Please check your console for errors.");
EditorUtility.DisplayDialog("Error during bundling", "There has been an error during the bundling process. Please check your console for errors.", "OK");
return;
}
2023-01-22 16:38:23 +01:00
AssetDatabase.Refresh();
2023-01-22 16:38:23 +01:00
EditorPrefs.SetBool("m_ABI_isBuilding", true);
EditorApplication.isPlaying = true;
}
#endregion
#region World Upload
2023-07-30 01:20:46 +02:00
public static async Task BuildAndUploadMapAsset(Scene scene, GameObject descriptor)
2023-01-22 16:38:23 +01:00
{
ClearLog();
EnforceVRSetting();
2023-01-22 16:38:23 +01:00
SetupNetworkUUIDs();
2023-07-30 01:20:46 +02:00
CVRAssetInfo assetInfo = descriptor.GetComponent<CVRAssetInfo>();
2023-07-30 01:20:46 +02:00
await InitializeAPIAndSetObjectId(assetInfo, "cck/generate/world");
SetAssetInfoDirty(assetInfo);
2023-01-22 16:38:23 +01:00
if (!HandlePreBuildEvent(PreWorldBundleEvent.Invoke, scene))
return;
2023-07-30 01:20:46 +02:00
2023-01-22 16:38:23 +01:00
PrefabUtility.SaveAsPrefabAsset(descriptor, "Assets/ABI.CCK/Resources/Cache/_CVRWorld.prefab");
AssetBundleBuild assetBundleBuild = new AssetBundleBuild();
assetBundleBuild.assetNames = new[] {scene.path};
assetBundleBuild.assetBundleName = "bundle.cvrworld";
BuildPipeline.BuildAssetBundles(Application.persistentDataPath, new[] {assetBundleBuild},
2023-07-30 01:20:46 +02:00
BuildAssetBundleOptions.ChunkBasedCompression, EditorUserBuildSettings.activeBuildTarget);
2023-01-22 16:38:23 +01:00
if (!File.Exists($"{Application.persistentDataPath}/bundle.cvrworld"))
{
Debug.LogError("Error during bundling\nThere has been an error during the bundling process. Please check your console for errors.");
EditorUtility.DisplayDialog("Error during bundling", "There has been an error during the bundling process. Please check your console for errors.", "OK");
return;
}
2023-01-22 16:38:23 +01:00
AssetDatabase.Refresh();
2023-01-22 16:38:23 +01:00
EditorPrefs.SetBool("m_ABI_isBuilding", true);
EditorApplication.isPlaying = true;
}
#endregion
#region Private Methods
private static async Task InitializeAPIAndSetObjectId(CVRAssetInfo assetInfo, string apiEndpoint)
{
if (string.IsNullOrEmpty(assetInfo.objectId))
{
#if UNITY_EDITOR
APIConnection.Initialize(EditorPrefs.GetString("m_ABI_Username"), EditorPrefs.GetString("m_ABI_Key"));
#endif
APIConnection.BaseResponse<APIConnection.GenerateResponse> response = await APIConnection.MakeRequest<APIConnection.GenerateResponse>(apiEndpoint, put: true);
if (response != null && response.Data != null)
assetInfo.objectId = response.Data.Id.ToString();
else
Debug.LogError($"[CCK:BuildUtility] New Guid could not be generated");
}
Random rnd = new Random();
assetInfo.randomNum = rnd.Next(11111111, 99999999).ToString();
}
private static void SetAssetInfoDirty(Component assetInfo)
{
EditorUtility.SetDirty(assetInfo);
EditorSceneManager.MarkSceneDirty(assetInfo.gameObject.scene);
EditorSceneManager.SaveScene(assetInfo.gameObject.scene);
}
private static GameObject InstantiateAndUnpackPrefab(GameObject original)
{
GameObject instantiated = Object.Instantiate(original);
if (PrefabUtility.IsPartOfNonAssetPrefabInstance(instantiated) && PrefabUtility.IsOutermostPrefabInstanceRoot(instantiated))
PrefabUtility.UnpackPrefabInstance(instantiated, PrefabUnpackMode.Completely, InteractionMode.AutomatedAction);
// Why would you do this?
if (instantiated.CompareTag("EditorOnly"))
instantiated.tag = "Untagged";
return instantiated;
}
private static bool HandlePreBuildEvent(Action<GameObject> preBuildEvent, GameObject instantiatedObject)
{
try
{
preBuildEvent.Invoke(instantiatedObject);
return true;
}
catch (Exception ex)
{
Debug.LogError($"[CCK:BuildUtility] Error occurred during PreBuildEvent: {ex.Message}");
return false;
}
}
private static bool HandlePreBuildEvent(Action<Scene> preBuildEvent, Scene scene)
{
try
{
preBuildEvent.Invoke(scene);
return true;
}
catch (Exception ex)
{
Debug.LogError($"[CCK:BuildUtility] Error occurred during PreBuildEvent: {ex.Message}");
return false;
}
}
private static void SetupNetworkUUIDs()
2023-01-22 16:38:23 +01:00
{
CVRInteractable[] interactables = Resources.FindObjectsOfTypeAll<CVRInteractable>();
CVRObjectSync[] objectSyncs = Resources.FindObjectsOfTypeAll<CVRObjectSync>();
CVRVideoPlayer[] videoPlayers = Resources.FindObjectsOfTypeAll<CVRVideoPlayer>();
CVRSpawnable[] spawnables = Resources.FindObjectsOfTypeAll<CVRSpawnable>();
GameInstanceController[] gameInstances = Resources.FindObjectsOfTypeAll<GameInstanceController>();
GunController[] gunControllers = Resources.FindObjectsOfTypeAll<GunController>();
List<string> UsedGuids = new List<string>();
foreach (var interactable in interactables)
{
foreach (var action in interactable.actions)
{
string guid;
do
{
guid = Guid.NewGuid().ToString();
} while (!string.IsNullOrEmpty(UsedGuids.Find(match => match == guid)));
UsedGuids.Add(guid);
action.guid = guid;
}
}
foreach (var objectSync in objectSyncs)
{
string guid;
do
{
guid = Guid.NewGuid().ToString();
} while (!string.IsNullOrEmpty(UsedGuids.Find(match => match == guid)));
UsedGuids.Add(guid);
var newserializedObject = new SerializedObject(objectSync);
newserializedObject.Update();
SerializedProperty _guidProperty = newserializedObject.FindProperty("guid");
_guidProperty.stringValue = guid;
newserializedObject.ApplyModifiedProperties();
}
foreach (var player in videoPlayers)
{
Guid res;
if (player.playerId == null || !Guid.TryParse(player.playerId, out res))
{
string guid;
do
{
guid = Guid.NewGuid().ToString();
} while (!string.IsNullOrEmpty(UsedGuids.Find(match => match == guid)));
UsedGuids.Add(guid);
player.playerId = guid;
}
}
foreach (var spawnable in spawnables)
{
string guid;
do
{
guid = Guid.NewGuid().ToString();
} while (!string.IsNullOrEmpty(UsedGuids.Find(match => match == guid)));
if (spawnable.preGeneratedInstanceId == "")
{
UsedGuids.Add(guid);
spawnable.preGeneratedInstanceId = "ws~" + guid;
}
else
{
UsedGuids.Add(spawnable.preGeneratedInstanceId);
}
spawnable.spawnableType = CVRSpawnable.SpawnableType.WorldSpawnable;
}
int i = 0;
foreach (GameInstanceController gameInstance in gameInstances)
{
if (gameInstance.teams.Count == 0)
{
var team = new Team();
team.name = "Team";
team.color = Color.red;
team.playerLimit = 16;
team.index = i;
gameInstance.teams.Add(team);
i++;
}
else
{
foreach (var team in gameInstance.teams)
{
team.index = i;
i++;
}
}
}
foreach (var gunController in gunControllers)
{
string guid;
do
{
guid = Guid.NewGuid().ToString();
} while (!string.IsNullOrEmpty(UsedGuids.Find(match => match == guid)));
UsedGuids.Add(guid);
var newserializedObject = new SerializedObject(gunController);
newserializedObject.Update();
SerializedProperty _guidProperty = newserializedObject.FindProperty("referenceID");
_guidProperty.stringValue = guid;
newserializedObject.ApplyModifiedProperties();
}
}
private static void ClearLog()
{
var assembly = Assembly.GetAssembly(typeof(UnityEditor.Editor));
var type = assembly.GetType("UnityEditor.LogEntries");
var method = type.GetMethod("Clear");
method.Invoke(new object(), null);
}
private static void EnforceVRSetting()
{
#if UNITY_2021_1_OR_NEWER
PlayerSettings.virtualRealitySupported = true;
PlayerSettings.stereoRenderingPath = StereoRenderingPath.Instancing;
XRSettings.enabled = false;
#else
PlayerSettings.virtualRealitySupported = true;
PlayerSettings.SetVirtualRealitySDKs(BuildTargetGroup.Standalone, new string[] { "None", "Oculus", "OpenVR", "MockHMD" });
PlayerSettings.stereoRenderingPath = StereoRenderingPath.SinglePass;
#endif
}
#endregion
2023-01-22 16:38:23 +01:00
}
#region PreBundleEvents
[Serializable]
public class PreAvatarBundleEvent : UnityEvent<GameObject> { }
2023-01-22 16:38:23 +01:00
[Serializable]
public class PrePropBundleEvent : UnityEvent<GameObject> { }
[Serializable]
public class PreWorldBundleEvent : UnityEvent<Scene> { }
#endregion
}