public static void StripPrefabsForQuest(GameObject gameObject) { foreach (TagZone zone in gameObject.GetComponentsInChildren <TagZone>(true)) { if (zone != null && zone.gameObject != null) { CreateQuestText("{\"TagZone\": true}", zone.gameObject); Object.DestroyImmediate(zone); } } foreach (SurfaceClimbSettings surfaceClimbSettings in gameObject.GetComponentsInChildren <SurfaceClimbSettings>(true)) { if (surfaceClimbSettings != null && surfaceClimbSettings.gameObject != null) { SurfaceClimbSettingsJSON settingsJson = new SurfaceClimbSettingsJSON(); settingsJson.Unclimbable = surfaceClimbSettings.Unclimbable; settingsJson.slipPercentage = surfaceClimbSettings.slipPercentage; CreateQuestText(JsonUtility.ToJson(settingsJson), surfaceClimbSettings.gameObject); Object.DestroyImmediate(surfaceClimbSettings); } } int triggerCount = 1; foreach (ObjectTrigger objectTrigger in gameObject.GetComponentsInChildren <ObjectTrigger>(true)) { if (objectTrigger != null && objectTrigger.gameObject != null) { string objectName = "ObjectTrigger" + triggerCount; if (objectTrigger.ObjectToTrigger != null) { CreateQuestText("{\"TriggeredBy\": \"" + objectName + "\"}", objectTrigger.ObjectToTrigger); } ObjectTriggerJSON triggerJSON = new ObjectTriggerJSON(); triggerJSON.ObjectTriggerName = objectName; triggerJSON.OnlyTriggerOnce = objectTrigger.OnlyTriggerOnce; triggerJSON.DisableObject = objectTrigger.DisableObject; CreateQuestText(JsonUtility.ToJson(triggerJSON), objectTrigger.gameObject); Object.DestroyImmediate(objectTrigger); triggerCount++; } } int teleporterCount = 1; foreach (Teleporter teleporter in gameObject.GetComponentsInChildren <Teleporter>(true)) { if (teleporter != null && teleporter.gameObject != null) { string teleporterName = "Teleporter" + teleporterCount; foreach (Transform teleportPoint in teleporter.TeleportPoints) { if (teleportPoint != null && teleportPoint.gameObject != null) { CreateQuestText("{\"TeleportPoint\": \"" + teleporterName + "\"}", teleportPoint.gameObject); } } teleporter.TeleportPoints = null; string teleporterJSON = JsonUtility.ToJson(teleporter); teleporterJSON = teleporterJSON.Replace("\"TeleportPoints\":[],", "\"TeleporterName\": \"" + teleporterName + "\","); CreateQuestText(teleporterJSON, teleporter.gameObject); Object.DestroyImmediate(teleporter); teleporterCount++; } } RoundEndActions roundEndActions = gameObject.GetComponentInChildren <RoundEndActions>(true); if (roundEndActions != null && roundEndActions.gameObject != null) { foreach (GameObject roundEndActionObject in roundEndActions.ObjectsToEnable) { if (roundEndActionObject != null) { CreateQuestText("{\"RoundEndAction\": \"Enable\"}", roundEndActionObject); } } foreach (GameObject roundEndActionObject in roundEndActions.ObjectsToDisable) { if (roundEndActionObject != null) { CreateQuestText("{\"RoundEndAction\": \"Disable\"}", roundEndActionObject); } } RoundEndActionsJSON actionsJSON = new RoundEndActionsJSON(); actionsJSON.RoundEndActions = true; actionsJSON.RespawnOnRoundEnd = roundEndActions.RespawnOnRoundEnd; CreateQuestText(JsonUtility.ToJson(actionsJSON), roundEndActions.gameObject); Object.DestroyImmediate(roundEndActions); } }
public static void ExportPackage(GameObject gameObject, string path, string typeName, PackageJSON packageJSON) { string fileName = Path.GetFileName(path); string folderPath = Path.GetDirectoryName(path); string androidFileName = Path.GetFileNameWithoutExtension(path) + "_android"; string pcFileName = Path.GetFileNameWithoutExtension(path) + "_pc"; string assetBundleScenePath = $"Assets/Editor/ExportScene.unity"; string oldScenePath = gameObject.scene.path; if (oldScenePath != null) { EditorSceneManager.SaveScene(gameObject.scene); } try { Selection.activeObject = gameObject; MapDescriptor mapDescriptor = gameObject.GetComponent <MapDescriptor>(); if (!mapDescriptor.ExportLighting) { Lightmapping.Clear(); Lightmapping.ClearLightingDataAsset(); } //EditorSceneManager.MarkSceneDirty(gameObject.scene); EditorSceneManager.SaveScene(gameObject.scene, assetBundleScenePath, true); EditorSceneManager.OpenScene(assetBundleScenePath); MapDescriptor[] descriptorList = Object.FindObjectsOfType <MapDescriptor>(); foreach (MapDescriptor descriptor in descriptorList) { if (descriptor.MapName != mapDescriptor.MapName) { Object.DestroyImmediate(descriptor.gameObject); } else { mapDescriptor = descriptor; gameObject = descriptor.gameObject; Selection.activeObject = gameObject; } } // First, unpack all prefabs foreach (GameObject subObject in GameObject.FindObjectsOfType <GameObject>()) { if (PrefabUtility.GetPrefabInstanceStatus(subObject) != PrefabInstanceStatus.NotAPrefab) { PrefabUtility.UnpackPrefabInstance(PrefabUtility.GetOutermostPrefabInstanceRoot(subObject), PrefabUnpackMode.Completely, InteractionMode.AutomatedAction); } } // Skybox Stuff if (mapDescriptor.CustomSkybox != null) { // Create Fake Skybox GameObject skybox = GameObject.CreatePrimitive(PrimitiveType.Sphere); skybox.name = "Skybox"; skybox.transform.SetParent(gameObject.transform); skybox.transform.localScale = new Vector3(1000, 1000, 1000); skybox.transform.localPosition = Vector3.zero; skybox.transform.localRotation = Quaternion.identity; Object.DestroyImmediate(skybox.GetComponent <Collider>()); Material skyboxMaterial = new Material(Shader.Find("Bobbie/Outer")); skyboxMaterial.SetTexture("_Tex", mapDescriptor.CustomSkybox); skybox.GetComponent <Renderer>().material = skyboxMaterial; skybox.GetComponent <Renderer>().shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off; } else { // Create Fake Skybox that represents the game's GameObject skyboxObject = AssetDatabase.LoadAssetAtPath("Assets/Prefabs/FakeSkybox.prefab", typeof(GameObject)) as GameObject; GameObject fakeSkybox = PrefabUtility.InstantiatePrefab(skyboxObject) as GameObject; fakeSkybox.transform.SetParent(gameObject.transform); fakeSkybox.transform.localPosition = Vector3.zero; } // Remove meshes from prefabs/triggers if (!DebugPrefabs) { StripMeshes <ObjectTrigger>(gameObject); StripMeshes <Teleporter>(gameObject); StripMeshes <TagZone>(gameObject); foreach (Renderer renderer in gameObject.GetComponentsInChildren <Renderer>()) { if (renderer.sharedMaterial != null && renderer.sharedMaterial.name.StartsWith("Teleport Point")) { Object.DestroyImmediate(renderer); } } StripMeshes <ObjectTrigger>(gameObject); } foreach (Renderer renderer in gameObject.GetComponentsInChildren <Renderer>()) { if (renderer.sharedMaterial != null && renderer.sharedMaterial.name.StartsWith("Spawn Point")) { bool foundTransform = false; foreach (Transform spawnPoint in mapDescriptor.SpawnPoints) { if (spawnPoint == renderer.gameObject.transform) { foundTransform = true; } } if (!foundTransform) { List <Transform> spawnPointArray = new List <Transform>(mapDescriptor.SpawnPoints); spawnPointArray.Add(renderer.gameObject.transform); mapDescriptor.SpawnPoints = spawnPointArray.ToArray(); } if (!DebugPrefabs) { Collider spawnPointCollider = renderer.gameObject.GetComponent <Collider>(); if (spawnPointCollider) { Object.DestroyImmediate(spawnPointCollider); } Object.DestroyImmediate(renderer); } } } if (mapDescriptor.SpawnPoints.Length == 0) { throw new System.Exception("No spawn points found! Add some spawn points to your map."); } // Take Screenshots with the thumbnail camera Camera thumbnailCamera = gameObject.transform.Find("ThumbnailCamera")?.GetComponent <Camera>(); if (thumbnailCamera != null) { // Normal Screenshot Texture2D screenshot = CaptureScreenshot(thumbnailCamera, 512, 512); byte[] screenshotPNG = ImageConversion.EncodeToPNG(screenshot); File.WriteAllBytes(Application.temporaryCachePath + "/preview.png", screenshotPNG); packageJSON.config.imagePath = "preview.png"; // Cubemap Screenshot Texture2D screenshotCubemap = CaptureCubemap(thumbnailCamera, 1024, 1024); byte[] screenshotCubemapPNG = ImageConversion.EncodeToPNG(screenshotCubemap); File.WriteAllBytes(Application.temporaryCachePath + "/preview_cubemap.png", screenshotCubemapPNG); packageJSON.config.cubemapImagePath = "preview_cubemap.png"; packageJSON.config.mapColor = AverageColor(screenshotCubemap); /* quest stuff (disabled for now) * byte[] screenshotRaw = screenshot.GetRawTextureData(); * File.WriteAllBytes(Application.temporaryCachePath + "/preview_quest", screenshotRaw); */ } Object.DestroyImmediate(thumbnailCamera.gameObject); // Pre-Process stuff for both platforms - PC and Android. GameObject spawnPointContainer = new GameObject("SpawnPointContainer"); spawnPointContainer.transform.SetParent(gameObject.transform); spawnPointContainer.transform.localPosition = Vector3.zero; spawnPointContainer.transform.localRotation = Quaternion.identity; spawnPointContainer.transform.localScale = Vector3.one; List <string> spawnPointNames = new List <string>(); for (int i = 0; i < mapDescriptor.SpawnPoints.Length; i++) { Transform spawnPointTransform = mapDescriptor.SpawnPoints[i].gameObject.transform; Vector3 oldPos = spawnPointTransform.position; var oldRotation = spawnPointTransform.rotation; spawnPointTransform.SetParent(spawnPointContainer.transform); spawnPointTransform.rotation = oldRotation; spawnPointTransform.position = oldPos; string nameString = "SpawnPoint" + (i < 10 ? "0" + i : i.ToString()); mapDescriptor.SpawnPoints[i].gameObject.name = nameString; spawnPointNames.Add(nameString); } packageJSON.config.spawnPoints = spawnPointNames.ToArray(); // Replace tiling materials with baked versions foreach (Renderer renderer in gameObject.GetComponentsInChildren <Renderer>()) { if (renderer.sharedMaterial != null && renderer.sharedMaterial.shader.name.Contains("Standard Tiling") && !renderer.sharedMaterial.shader.name.Contains("Baked")) { renderer.sharedMaterial = Object.Instantiate(renderer.sharedMaterial); renderer.sharedMaterial.shader = Shader.Find("Standard Tiling Baked"); Transform rendererTransform = renderer.gameObject.transform; Vector3 newVector = RotatePointAroundPivot(rendererTransform.lossyScale, new Vector3(0, 0, 0), rendererTransform.rotation.eulerAngles); renderer.sharedMaterial.SetVector("_ScaleVector", newVector); } } // Destroy all non-render cameras because people keep accidentally exporting them foreach (Camera camera in gameObject.GetComponentsInChildren <Camera>()) { if (camera.targetTexture == null && camera.gameObject != null) { Object.DestroyImmediate(camera.gameObject); } } // Lighting stuff. Make sure to set light stuff up and make it bigger, and bake if (mapDescriptor.ExportLighting) { foreach (Light light in Object.FindObjectsOfType <Light>()) { if (light.type == LightType.Directional) { light.intensity *= 11.54f; light.color = new Color(0.3215f, 0.3215f, 0.3215f); } else { light.intensity *= 10f; } } Lightmapping.Bake(); } else { foreach (Light light in Object.FindObjectsOfType <Light>()) { Object.DestroyImmediate(light); } Lightmapping.Clear(); Lightmapping.ClearLightingDataAsset(); } gameObject.transform.localPosition = new Vector3(0, 5000, 0); // Save as prefab and build // PrefabUtility.SaveAsPrefabAsset(Selection.activeObject as GameObject, $"Assets/_{typeName}.prefab"); EditorSceneManager.SaveScene(gameObject.scene); AssetBundleBuild assetBundleBuild = default; assetBundleBuild.assetNames = new string[] { assetBundleScenePath }; assetBundleBuild.assetBundleName = pcFileName; // Build for PC BuildPipeline.BuildAssetBundles(Application.temporaryCachePath, new AssetBundleBuild[] { assetBundleBuild }, 0, BuildTarget.StandaloneWindows64); // Do Android specific stuff here. Stripping MonoBehaviours and converting them to TextAssets, etc. // first we need to redo this bit of code because sometimes gameObject unreferences itself MapDescriptor[] descriptorList2 = Object.FindObjectsOfType <MapDescriptor>(); foreach (MapDescriptor descriptor in descriptorList2) { if (descriptor.MapName != mapDescriptor.MapName) { Object.DestroyImmediate(descriptor.gameObject); } else { mapDescriptor = descriptor; gameObject = descriptor.gameObject; Selection.activeObject = gameObject; } } foreach (TagZone zone in gameObject.GetComponentsInChildren <TagZone>(true)) { if (zone != null && zone.gameObject != null) { CreateQuestText("{\"TagZone\": true}", zone.gameObject); Object.DestroyImmediate(zone); } } foreach (SurfaceClimbSettings surfaceClimbSettings in gameObject.GetComponentsInChildren <SurfaceClimbSettings>(true)) { if (surfaceClimbSettings != null && surfaceClimbSettings.gameObject != null) { SurfaceClimbSettingsJSON settingsJson = new SurfaceClimbSettingsJSON(); settingsJson.Unclimbable = surfaceClimbSettings.Unclimbable; settingsJson.slipPercentage = surfaceClimbSettings.slipPercentage; CreateQuestText(JsonUtility.ToJson(settingsJson), surfaceClimbSettings.gameObject); Object.DestroyImmediate(surfaceClimbSettings); } } int triggerCount = 1; foreach (ObjectTrigger objectTrigger in gameObject.GetComponentsInChildren <ObjectTrigger>(true)) { if (objectTrigger != null && objectTrigger.gameObject != null) { string objectName = "ObjectTrigger" + triggerCount; if (objectTrigger.ObjectToTrigger != null) { CreateQuestText("{\"TriggeredBy\": \"" + objectName + "\"}", objectTrigger.ObjectToTrigger); } ObjectTriggerJSON triggerJSON = new ObjectTriggerJSON(); triggerJSON.ObjectTriggerName = objectName; triggerJSON.OnlyTriggerOnce = objectTrigger.OnlyTriggerOnce; triggerJSON.DisableObject = objectTrigger.DisableObject; CreateQuestText(JsonUtility.ToJson(triggerJSON), objectTrigger.gameObject); Object.DestroyImmediate(objectTrigger); triggerCount++; } } int teleporterCount = 1; foreach (Teleporter teleporter in gameObject.GetComponentsInChildren <Teleporter>(true)) { if (teleporter != null && teleporter.gameObject != null) { string teleporterName = "Teleporter" + teleporterCount; foreach (Transform teleportPoint in teleporter.TeleportPoints) { if (teleportPoint != null && teleportPoint.gameObject != null) { CreateQuestText("{\"TeleportPoint\": \"" + teleporterName + "\"}", teleportPoint.gameObject); } } teleporter.TeleportPoints = null; string teleporterJSON = JsonUtility.ToJson(teleporter); teleporterJSON = teleporterJSON.Replace("\"TeleportPoints\":[],", "\"TeleporterName\": \"" + teleporterName + "\","); CreateQuestText(teleporterJSON, teleporter.gameObject); Object.DestroyImmediate(teleporter); teleporterCount++; } } RoundEndActions roundEndActions = gameObject.GetComponentInChildren <RoundEndActions>(true); if (roundEndActions != null && roundEndActions.gameObject != null) { foreach (GameObject roundEndActionObject in roundEndActions.ObjectsToEnable) { if (roundEndActionObject != null) { CreateQuestText("{\"RoundEndAction\": \"Enable\"}", roundEndActionObject); } } foreach (GameObject roundEndActionObject in roundEndActions.ObjectsToDisable) { if (roundEndActionObject != null) { CreateQuestText("{\"RoundEndAction\": \"Disable\"}", roundEndActionObject); } } RoundEndActionsJSON actionsJSON = new RoundEndActionsJSON(); actionsJSON.RoundEndActions = true; actionsJSON.RespawnOnRoundEnd = roundEndActions.RespawnOnRoundEnd; CreateQuestText(JsonUtility.ToJson(actionsJSON), roundEndActions.gameObject); Object.DestroyImmediate(roundEndActions); } Object.DestroyImmediate(mapDescriptor); // Do it again for Android EditorSceneManager.SaveScene(gameObject.scene); // PrefabUtility.SaveAsPrefabAsset(Selection.activeObject as GameObject, $"Assets/_{typeName}.prefab"); // are these next 2 lines necessary? idk. probably test it. assetBundleBuild.assetNames = new string[] { assetBundleScenePath }; assetBundleBuild.assetBundleName = androidFileName; BuildPipeline.BuildAssetBundles(Application.temporaryCachePath, new AssetBundleBuild[] { assetBundleBuild }, 0, BuildTarget.Android); EditorPrefs.SetString("currentBuildingAssetBundlePath", folderPath); // JSON stuff packageJSON.androidFileName = androidFileName; packageJSON.pcFileName = pcFileName; string json = JsonUtility.ToJson(packageJSON, true); File.WriteAllText(Application.temporaryCachePath + "/package.json", json); // AssetDatabase.DeleteAsset($"Assets/_{typeName}.prefab"); // Delete the zip if it already exists and re-zip List <string> files = new List <string> { Application.temporaryCachePath + "/" + pcFileName, Application.temporaryCachePath + "/" + androidFileName, Application.temporaryCachePath + "/package.json", Application.temporaryCachePath + "/preview.png", Application.temporaryCachePath + "/preview_cubemap.png" }; if (File.Exists(Application.temporaryCachePath + "/tempZip.zip")) { File.Delete(Application.temporaryCachePath + "/tempZip.zip"); } CreateZipFile(Application.temporaryCachePath + "/tempZip.zip", files); // After zipping, clear some assets from the temp folder if (File.Exists(path)) { File.Delete(path); } foreach (string file in files) { if (File.Exists(file)) { File.Delete(file); } } // Move the ZIP and finalize File.Move(Application.temporaryCachePath + "/tempZip.zip", path); //Object.DestroyImmediate(gameObject); AssetDatabase.Refresh(); // Open scene again EditorSceneManager.OpenScene(oldScenePath); } catch (System.Exception e) { Debug.Log("Something went wrong... let's load the old scene."); if (oldScenePath != null) { EditorSceneManager.OpenScene(oldScenePath); } else { throw new System.Exception("Something went wrong and you don't have your work saved in a scene! PLEASE save your work in a scene before trying to export."); } throw e; } }