diff --git a/Editor/ScenePartitionDataSO.cs b/Editor/ScenePartitionDataSO.cs index f5775e4..714264e 100644 --- a/Editor/ScenePartitionDataSO.cs +++ b/Editor/ScenePartitionDataSO.cs @@ -5,10 +5,12 @@ namespace VertexColor.ScenePartition.Editor [CreateAssetMenu(fileName = "Scene", menuName = "Max/ScenePartitionDataSO")] public class ScenePartitionDataSO : ScriptableObject { - public bool hasCreatedPartitions => scenePartitions != null && scenePartitions.Count > 0; - public SerializableSortedList scenePartitions = new SerializableSortedList(); + public bool HasCreatedPartitions => ScenePartitions != null && ScenePartitions.Count > 0; + public ScenePartitionSortedList ScenePartitions = new ScenePartitionSortedList(); - public bool hasLoadedPartitions => loadedScenePartitions != null && loadedScenePartitions.Count > 0; - public SerializableSortedList loadedScenePartitions = new SerializableSortedList(); + public bool HasLoadedPartitions => LoadedScenePartitions != null && LoadedScenePartitions.Count > 0; + public ScenePartitionSortedList LoadedScenePartitions = new ScenePartitionSortedList(); + + public SceneGrid SceneGrid = new SceneGrid(); } } \ No newline at end of file diff --git a/Editor/ScenePartitionDataSOEditor.cs b/Editor/ScenePartitionDataSOEditor.cs index 0d2fab5..7971b6e 100644 --- a/Editor/ScenePartitionDataSOEditor.cs +++ b/Editor/ScenePartitionDataSOEditor.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using UnityEditor; +using UnityEngine; namespace VertexColor.ScenePartition.Editor { @@ -18,48 +19,35 @@ public override void OnInspectorGUI() EditorGUILayout.Space(); + if (GUILayout.Button("Force Serialize")) + { + AssetDatabase.ForceReserializeAssets(new string[] { AssetDatabase.GetAssetPath(scenePartitionDataSO) }, ForceReserializeAssetsOptions.ReserializeAssetsAndMetadata); + } + using (new EditorGUI.DisabledGroupScope(true)) { - if (scenePartitionDataSO.hasCreatedPartitions) + if (scenePartitionDataSO.HasCreatedPartitions) { EditorGUILayout.LabelField($"scenePartitions"); - foreach (KeyValuePair scenePartition in scenePartitionDataSO.scenePartitions) + foreach (KeyValuePair scenePartition in scenePartitionDataSO.ScenePartitions) { EditorGUILayout.IntField((int)scenePartition.Value.id); - if (scenePartition.Value.references != null && scenePartition.Value.references.Count > 0) - { - EditorGUI.indentLevel++; - foreach (var reference in scenePartition.Value.references) - { - EditorGUILayout.IntField((int)reference); - } - EditorGUI.indentLevel--; - } } } EditorGUILayout.Space(); - if (scenePartitionDataSO.hasLoadedPartitions) + if (scenePartitionDataSO.HasLoadedPartitions) { EditorGUILayout.LabelField($"loadedScenePartitions"); - foreach (KeyValuePair scenePartition in scenePartitionDataSO.loadedScenePartitions) + foreach (KeyValuePair scenePartition in scenePartitionDataSO.LoadedScenePartitions) { EditorGUILayout.IntField((int)scenePartition.Value.id); - if (scenePartition.Value.references != null && scenePartition.Value.references.Count > 0) - { - EditorGUI.indentLevel++; - foreach (var reference in scenePartition.Value.references) - { - EditorGUILayout.IntField((int)reference); - } - EditorGUI.indentLevel--; - } } } } } } -} +} \ No newline at end of file diff --git a/Editor/ScenePartitionSO.cs b/Editor/ScenePartitionSO.cs index c91c335..3a5e989 100644 --- a/Editor/ScenePartitionSO.cs +++ b/Editor/ScenePartitionSO.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.IO; +using System.Text.RegularExpressions; using UnityEditor; using UnityEditor.SceneManagement; using UnityEngine; @@ -11,15 +12,17 @@ namespace VertexColor.ScenePartition.Editor public class ScenePartitionSO : ScriptableObject { [field: SerializeField] - public SceneAsset sceneAsset { get; private set; } = null; - public string sceneName => sceneAsset == null ? name : sceneAsset.name; - public ScenePartitionDataSO scenePartitionData = null; + public SceneAsset SceneAsset { get; private set; } = null; + public string SceneName => SceneAsset == null ? name : SceneAsset.name; + + [SerializeField] + private ScenePartitionDataSO scenePartitionData = null; public List alwaysLoadIds = new List { 0, 1, 2, 3, 4 }; public void CreateScene() { - if (sceneAsset != null) return; + if (SceneAsset != null) return; string scenePath = Path.Combine(AssetDatabase.GetAssetPath(this), $"../{this.name}.unity"); @@ -28,7 +31,7 @@ public void CreateScene() AssetDatabase.Refresh(); - sceneAsset = AssetDatabase.LoadAssetAtPath(scenePath); + SceneAsset = AssetDatabase.LoadAssetAtPath(scenePath); AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); @@ -39,9 +42,13 @@ public void CreateScene() /// public void LoadAll() { + AssetDatabase.StartAssetEditing(); + CreateScenePartitions(); - SortedSet ids = new SortedSet(scenePartitionData.scenePartitions.Keys); + SortedSet ids = new SortedSet(scenePartitionData.ScenePartitions.Keys); LoadScenePartitions(ids); + + AssetDatabase.StopAssetEditing(); } private void CreateScenePartitions() @@ -49,29 +56,29 @@ private void CreateScenePartitions() string dataPath = ScenePartitionUtils.GetDataPath(this); string[] files = Directory.GetFiles(dataPath); - scenePartitionData.scenePartitions = new SerializableSortedList(); + scenePartitionData.ScenePartitions = new ScenePartitionSortedList(); for (int i = 0; i < files.Length; i++) { ScenePartition scenePartition = new ScenePartition(files[i]); - scenePartitionData.scenePartitions.Add(scenePartition.id, scenePartition); + scenePartitionData.ScenePartitions.Add(scenePartition.id, scenePartition); } } private void LoadScenePartitions(SortedSet partitionIds) { - if (!scenePartitionData.hasCreatedPartitions) return; + if (!scenePartitionData.HasCreatedPartitions) return; string scenePath = ScenePartitionUtils.GetScenePath(this); List data = new List(); - scenePartitionData.loadedScenePartitions.Clear(); + scenePartitionData.LoadedScenePartitions.Clear(); // Add default ids. for (int i = 0; i < alwaysLoadIds.Count; i++) { - if (scenePartitionData.scenePartitions.ContainsKey(alwaysLoadIds[i])) + if (scenePartitionData.ScenePartitions.ContainsKey(alwaysLoadIds[i])) { partitionIds.Add(alwaysLoadIds[i]); } @@ -80,9 +87,9 @@ private void LoadScenePartitions(SortedSet partitionIds) // Create scene data. foreach (uint id in partitionIds) { - ScenePartition p = scenePartitionData.scenePartitions[id]; - data.AddRange(p.data); - scenePartitionData.loadedScenePartitions.Add(p.id, p); + ScenePartition p = scenePartitionData.ScenePartitions[id]; + data.AddRange(File.ReadAllLines(p.filePath)); + scenePartitionData.LoadedScenePartitions.Add(p.id, p); } // Create scene. @@ -96,33 +103,41 @@ private void LoadScenePartitions(SortedSet partitionIds) /// public void Save() { - if (!scenePartitionData.hasCreatedPartitions) return; - if (!scenePartitionData.hasLoadedPartitions) return; + if (!scenePartitionData.HasCreatedPartitions) return; + if (!scenePartitionData.HasLoadedPartitions) return; DeleteLoadedPartitions(); // Delete the loaded partitions from disk so we can write the new ones. + string pattern = @"&(\d+)"; string dataPath = ScenePartitionUtils.GetDataPath(this); string scenePath = ScenePartitionUtils.GetScenePath(this); + // Read the data from the scene file. string[] data = File.ReadAllLines(scenePath); + // Split it into blocks. 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; + Match match = Regex.Match(data[i], pattern); - File.WriteAllLines($"{dataPath}/{sceneName}-{data[i][idStartIndex..idLength]}.yaml", data[i..lastIndex]); + if (match.Success) + { + // Extract the file number + string id = match.Groups[1].Value; + + // Write data to disk. + File.WriteAllLines($"{dataPath}/{SceneName}-{id}.yaml", data[i..lastIndex]); + } lastIndex = i; } } - File.WriteAllLines($"{dataPath}/{sceneName}.yaml", data[0..lastIndex]); - - LoadAll(); // Reload. + // Write header to disk. + File.WriteAllLines($"{dataPath}/{SceneName}.yaml", data[0..lastIndex]); } /// @@ -144,23 +159,21 @@ public void Unload() EditorSceneManager.SaveScene(scene); - scenePartitionData.scenePartitions.Clear(); + scenePartitionData.LoadedScenePartitions.Clear(); AssetDatabase.Refresh(); } private void DeleteLoadedPartitions() { - if (!scenePartitionData.hasCreatedPartitions) return; + if (!scenePartitionData.HasCreatedPartitions) return; - foreach (KeyValuePair scenePartition in scenePartitionData.scenePartitions) + foreach (KeyValuePair scenePartition in scenePartitionData.LoadedScenePartitions) { if (!File.Exists(scenePartition.Value.filePath)) continue; File.Delete(scenePartition.Value.filePath); } - - scenePartitionData.loadedScenePartitions.Clear(); } public void LoadPartitions(uint[] ids) @@ -169,7 +182,7 @@ public void LoadPartitions(uint[] ids) for (int i = 0; i < ids.Length; i++) { - SortedSet connections = ScenePartitionUtils.FindDeeplyLinkedObjects(scenePartitionData.scenePartitions, ids[i]); + SortedSet connections = ScenePartitionUtils.FindDeeplyLinkedObjects(scenePartitionData.ScenePartitions, ids[i]); foreach (uint c in connections) { diff --git a/Editor/ScenePartitionSOEditor.cs b/Editor/ScenePartitionSOEditor.cs index 20558b4..b39d347 100644 --- a/Editor/ScenePartitionSOEditor.cs +++ b/Editor/ScenePartitionSOEditor.cs @@ -20,7 +20,7 @@ public override void OnInspectorGUI() EditorGUILayout.Space(); - if (scenePartitionSO.sceneAsset == null) + if (scenePartitionSO.SceneAsset == null) { if (GUILayout.Button("Create Scene")) { @@ -34,12 +34,9 @@ public override void OnInspectorGUI() scenePartitionSO.LoadAll(); } - if (scenePartitionSO.scenePartitionData.hasCreatedPartitions) + if (GUILayout.Button("Save")) { - if (GUILayout.Button("Save")) - { - scenePartitionSO.Save(); - } + scenePartitionSO.Save(); } if (GUILayout.Button("Unload")) diff --git a/Editor/ScenePartitionUtils.cs b/Editor/ScenePartitionUtils.cs index af177ea..d90aca3 100644 --- a/Editor/ScenePartitionUtils.cs +++ b/Editor/ScenePartitionUtils.cs @@ -21,7 +21,7 @@ public static string GetDataPath(ScenePartitionSO scenePartitionSO) public static string GetScenePath(ScenePartitionSO scenePartitionSO) { - string scenePath = AssetDatabase.GetAssetOrScenePath(scenePartitionSO.sceneAsset); + string scenePath = AssetDatabase.GetAssetOrScenePath(scenePartitionSO.SceneAsset); return scenePath; } diff --git a/Runtime/SceneGrid.cs b/Runtime/SceneGrid.cs new file mode 100644 index 0000000..84c5a97 --- /dev/null +++ b/Runtime/SceneGrid.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace VertexColor.ScenePartition.Editor +{ + [Serializable] + public class SceneGrid + { + [SerializeField] + private int cellSize = 10; + + [SerializeField] + private SceneGridDictionary grid = new SceneGridDictionary(); + + public void Insert(uint id, Vector2 point) + { + Vector2 gridPos = CalculateGridPosition(point); + if (grid.TryGetValue(gridPos, out List ids)) + { + ids.Add(id); + } + else + { + grid.Add(gridPos, new List { id }); + } + } + + public Vector2 CalculateGridPosition(Vector2 point) + { + int x = Mathf.FloorToInt(point.x / cellSize); + int y = Mathf.FloorToInt(point.y / cellSize); + + return new Vector2(x, y); + } + } +} diff --git a/Runtime/SceneGrid.cs.meta b/Runtime/SceneGrid.cs.meta new file mode 100644 index 0000000..3bab06b --- /dev/null +++ b/Runtime/SceneGrid.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f10fd4b244f804943a8ade09f4f46771 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/ScenePartition.cs b/Runtime/ScenePartition.cs similarity index 88% rename from Editor/ScenePartition.cs rename to Runtime/ScenePartition.cs index 130faa6..6ce135c 100644 --- a/Editor/ScenePartition.cs +++ b/Runtime/ScenePartition.cs @@ -2,7 +2,7 @@ using System.IO; using System.Text.RegularExpressions; -namespace VertexColor.ScenePartition.Editor +namespace VertexColor.ScenePartition { public class SceneIdComparer : IComparer { @@ -26,14 +26,14 @@ public class ScenePartition { public uint id = 0; public string filePath = null; - public string[] data = null; - public SerializableSortedSet references = new SerializableSortedSet(); + //public string[] data = null; + public UintSortedSet references = new UintSortedSet(); public ScenePartition(string filePath) { this.filePath = filePath; - data = File.ReadAllLines(filePath); + string[] data = File.ReadAllLines(filePath); if (data == null || data.Length == 0) return; diff --git a/Editor/ScenePartition.cs.meta b/Runtime/ScenePartition.cs.meta similarity index 100% rename from Editor/ScenePartition.cs.meta rename to Runtime/ScenePartition.cs.meta diff --git a/Runtime/SerializationUtility.cs b/Runtime/SerializationUtility.cs index e69202d..3f49edc 100644 --- a/Runtime/SerializationUtility.cs +++ b/Runtime/SerializationUtility.cs @@ -1,26 +1,26 @@ -using System; using System.Collections.Generic; using UnityEngine; namespace VertexColor.ScenePartition { - [Serializable] + [System.Serializable] public class SerializableDictionary : Dictionary, ISerializationCallbackReceiver { [SerializeField] - private List keys = new List(); + private List dictionaryKeys = new List(); + [SerializeField] - private List values = new List(); + private List dictionaryValues = new List(); public void OnBeforeSerialize() { - keys.Clear(); - values.Clear(); + dictionaryKeys.Clear(); + dictionaryValues.Clear(); - foreach (KeyValuePair pair in this) + foreach (KeyValuePair item in this) { - keys.Add(pair.Key); - values.Add(pair.Value); + dictionaryKeys.Add(item.Key); + dictionaryValues.Add(item.Value); } } @@ -28,35 +28,33 @@ public void OnAfterDeserialize() { Clear(); - if (keys.Count != values.Count) - { - throw new Exception("Error: Key and value count does not match in the dictionary."); - } + if (dictionaryKeys.Count != dictionaryValues.Count) return; - for (int i = 0; i < keys.Count; i++) + for (int i = 0; i < dictionaryKeys.Count; i++) { - Add(keys[i], values[i]); + Add(dictionaryKeys[i], dictionaryValues[i]); } } } - [Serializable] + [System.Serializable] public class SerializableSortedList : SortedList, ISerializationCallbackReceiver { [SerializeField] - private List keys = new List(); + private List sortedListKeys = new List(); + [SerializeField] - private List values = new List(); + private List sortedListValues = new List(); public void OnBeforeSerialize() { - keys.Clear(); - values.Clear(); + sortedListKeys.Clear(); + sortedListValues.Clear(); - foreach (KeyValuePair pair in this) + foreach (KeyValuePair item in this) { - keys.Add(pair.Key); - values.Add(pair.Value); + sortedListKeys.Add(item.Key); + sortedListValues.Add(item.Value); } } @@ -64,37 +62,34 @@ public void OnAfterDeserialize() { Clear(); - if (keys.Count != values.Count) - { - throw new Exception("Error: Key and value count does not match in the dictionary."); - } + if (sortedListKeys.Count != sortedListValues.Count) return; - for (int i = 0; i < keys.Count; i++) + for (int i = 0; i < sortedListKeys.Count; i++) { - Add(keys[i], values[i]); + Add(sortedListKeys[i], sortedListValues[i]); } } } - [Serializable] + [System.Serializable] public class SerializableSortedSet : SortedSet, ISerializationCallbackReceiver { [SerializeField] - private List elements = new List(); + private List sortedSetValues = new List(); public void OnBeforeSerialize() { - elements.Clear(); - elements.AddRange(this); + sortedSetValues.Clear(); + sortedSetValues.AddRange(this); } public void OnAfterDeserialize() { Clear(); - for (int i = 0; i < elements.Count; i++) + for (int i = 0; i < sortedSetValues.Count; i++) { - Add(elements[i]); + Add(sortedSetValues[i]); } } } diff --git a/Runtime/SerializedStructures.cs b/Runtime/SerializedStructures.cs new file mode 100644 index 0000000..42245bd --- /dev/null +++ b/Runtime/SerializedStructures.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace VertexColor.ScenePartition +{ + [System.Serializable] + public class ScenePartitionSortedList : SerializableSortedList { } + + [System.Serializable] + public class UintSortedSet : SerializableSortedSet { } + + [System.Serializable] + public class SceneGridDictionary : SerializableDictionary> { } +} \ No newline at end of file diff --git a/Runtime/SerializedStructures.cs.meta b/Runtime/SerializedStructures.cs.meta new file mode 100644 index 0000000..80b1d13 --- /dev/null +++ b/Runtime/SerializedStructures.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b87f21b6a1ebd2749b49c3a1812498e0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: