using System.Collections.Generic; using System.IO; using System.Linq; using UnityEditor; using UnityEditor.SceneManagement; using UnityEngine; using UnityEngine.SceneManagement; namespace VertexColor.ScenePartition.Editor { [CreateAssetMenu(fileName = "Scene", menuName = "Max/ScenePartitionSO")] public class ScenePartitionSO : ScriptableObject { [field: SerializeField] public SceneAsset sceneAsset { get; private set; } = null; public string sceneName { get; private set; } = ""; public bool hasLoadedPartitions => (loadedPartitions != null && loadedPartitions.Count > 0); [SerializeField] private List loadedPartitions = null; // Should not be serialized, this would be local data only. public void CreateScene() { if (sceneAsset != null) return; string scenePath = Path.Combine(AssetDatabase.GetAssetPath(this), $"../{this.name}.unity"); Scene scene = EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single); EditorSceneManager.SaveScene(scene, scenePath); AssetDatabase.Refresh(); } public void LoadAll() { string dataPath = ScenePartitionUtils.GetDataPath(this); string scenePath = ScenePartitionUtils.GetScenePath(this); List data = new List(); List files = Directory.GetFiles(dataPath).ToList(); files.Sort(); for (int i = 0; i < files.Count; i++) { data.AddRange(File.ReadAllLines(files[i])); } File.WriteAllLines(scenePath, data); loadedPartitions.AddRange(files); AssetDatabase.Refresh(); } public void SaveAll() { if (!hasLoadedPartitions) return; DeleteLoadedPartitions(); string dataPath = ScenePartitionUtils.GetDataPath(this); string scenePath = ScenePartitionUtils.GetScenePath(this); string[] data = File.ReadAllLines(scenePath); int lastIndex = data.Length; for (int i = data.Length - 1; i >= 0; i--) { if (data[i].StartsWith("---")) // --- is the start of a new yaml document. { int idStartIndex = data[i].IndexOf(" &") + 2; // & is the start of the object id. int idLength = data[i].Length; File.WriteAllLines($"{dataPath}/{sceneName}-{data[i][idStartIndex..idLength]}.yaml", data[i..lastIndex]); lastIndex = i; } } File.WriteAllLines($"{dataPath}/{sceneName}.yaml", data[0..lastIndex]); } public void Unload() { string dataPath = ScenePartitionUtils.GetDataPath(this); string scenePath = ScenePartitionUtils.GetScenePath(this); Scene scene = EditorSceneManager.OpenScene(scenePath, OpenSceneMode.Single); GameObject[] gameObjects = scene.GetRootGameObjects(); for (int i = gameObjects.Length - 1; i >= 0; i--) { Object.DestroyImmediate(gameObjects[i]); } EditorSceneManager.SaveScene(scene); loadedPartitions.Clear(); AssetDatabase.Refresh(); } private void DeleteLoadedPartitions() { if (loadedPartitions == null) return; for (int i = loadedPartitions.Count - 1; i >= 0; i--) { if (!File.Exists(loadedPartitions[i])) continue; File.Delete(loadedPartitions[i]); } loadedPartitions.Clear(); } private void OnValidate() { if (string.IsNullOrWhiteSpace(sceneName) && sceneAsset != null) { sceneName = sceneAsset.name; } } } }