SerializationUtility

- Split local editor data into separate SO
- Serializable dicts, sorted lists and sorted sets
- Only delete and save loaded partitions
This commit is contained in:
max 2023-06-25 15:51:54 +02:00
parent b067522a95
commit 3bba6da1a6
9 changed files with 243 additions and 65 deletions

View File

@ -27,7 +27,7 @@ public class ScenePartition
public uint id = 0; public uint id = 0;
public string filePath = null; public string filePath = null;
public string[] data = null; public string[] data = null;
public HashSet<uint> references = new HashSet<uint>(); public SerializableSortedSet<uint> references = new SerializableSortedSet<uint>();
public ScenePartition(string filePath) public ScenePartition(string filePath)
{ {

View File

@ -0,0 +1,14 @@
using UnityEngine;
namespace VertexColor.ScenePartition.Editor
{
[CreateAssetMenu(fileName = "Scene", menuName = "Max/ScenePartitionDataSO")]
public class ScenePartitionDataSO : ScriptableObject
{
public bool hasCreatedPartitions => scenePartitions != null && scenePartitions.Count > 0;
public SerializableSortedList<uint, ScenePartition> scenePartitions = new SerializableSortedList<uint, ScenePartition>();
public bool hasLoadedPartitions => loadedScenePartitions != null && loadedScenePartitions.Count > 0;
public SerializableSortedList<uint, ScenePartition> loadedScenePartitions = new SerializableSortedList<uint, ScenePartition>();
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 53d6bea45132f6d4aa3aa1631099564e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,65 @@
using System.Collections.Generic;
using UnityEditor;
namespace VertexColor.ScenePartition.Editor
{
[CustomEditor(typeof(ScenePartitionDataSO))]
public class ScenePartitionDataSOEditor : UnityEditor.Editor
{
public override void OnInspectorGUI()
{
ScenePartitionDataSO scenePartitionDataSO = (target as ScenePartitionDataSO);
DrawDefaultInspector();
serializedObject.Update();
//EditorGUILayout.PropertyField(sceneAssetProperty);
serializedObject.ApplyModifiedProperties();
EditorGUILayout.Space();
using (new EditorGUI.DisabledGroupScope(true))
{
if (scenePartitionDataSO.hasCreatedPartitions)
{
EditorGUILayout.LabelField($"scenePartitions");
foreach (KeyValuePair<uint, ScenePartition> 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)
{
EditorGUILayout.LabelField($"loadedScenePartitions");
foreach (KeyValuePair<uint, ScenePartition> 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--;
}
}
}
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7b9bf98e36efc7b4dbac2b8a7be74407
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -13,12 +13,9 @@ public class ScenePartitionSO : ScriptableObject
[field: SerializeField] [field: SerializeField]
public SceneAsset sceneAsset { get; private set; } = null; public SceneAsset sceneAsset { get; private set; } = null;
public string sceneName => sceneAsset == null ? name : sceneAsset.name; public string sceneName => sceneAsset == null ? name : sceneAsset.name;
public ScenePartitionDataSO scenePartitionData = null;
public bool hasCreatedPartitions => scenePartitions != null && scenePartitions.Count > 0; public List<uint> alwaysLoadIds = new List<uint> { 0, 1, 2, 3, 4 };
public SortedList<uint, ScenePartition> scenePartitions = null;
public bool hasLoadedPartitions => loadedScenePartitions != null && loadedScenePartitions.Count > 0;
public SortedList<uint, ScenePartition> loadedScenePartitions = null;
public void CreateScene() public void CreateScene()
{ {
@ -43,7 +40,7 @@ public void CreateScene()
public void LoadAll() public void LoadAll()
{ {
CreateScenePartitions(); CreateScenePartitions();
SortedSet<uint> ids = new SortedSet<uint>(scenePartitions.Keys); SortedSet<uint> ids = new SortedSet<uint>(scenePartitionData.scenePartitions.Keys);
LoadScenePartitions(ids); LoadScenePartitions(ids);
} }
@ -52,34 +49,40 @@ private void CreateScenePartitions()
string dataPath = ScenePartitionUtils.GetDataPath(this); string dataPath = ScenePartitionUtils.GetDataPath(this);
string[] files = Directory.GetFiles(dataPath); string[] files = Directory.GetFiles(dataPath);
scenePartitions = new SortedList<uint, ScenePartition>(); scenePartitionData.scenePartitions = new SerializableSortedList<uint, ScenePartition>();
for (int i = 0; i < files.Length; i++) for (int i = 0; i < files.Length; i++)
{ {
ScenePartition scenePartition = new ScenePartition(files[i]); ScenePartition scenePartition = new ScenePartition(files[i]);
scenePartitions.Add(scenePartition.id, scenePartition); scenePartitionData.scenePartitions.Add(scenePartition.id, scenePartition);
} }
} }
private void LoadScenePartitions(SortedSet<uint> partitionIds) private void LoadScenePartitions(SortedSet<uint> partitionIds)
{ {
if (!hasCreatedPartitions) return; if (!scenePartitionData.hasCreatedPartitions) return;
string scenePath = ScenePartitionUtils.GetScenePath(this); string scenePath = ScenePartitionUtils.GetScenePath(this);
List<string> data = new List<string>(); List<string> data = new List<string>();
loadedScenePartitions = new SortedList<uint, ScenePartition>(); scenePartitionData.loadedScenePartitions.Clear();
// Add the header. // Add default ids.
partitionIds.Add(0); for (int i = 0; i < alwaysLoadIds.Count; i++)
{
if (scenePartitionData.scenePartitions.ContainsKey(alwaysLoadIds[i]))
{
partitionIds.Add(alwaysLoadIds[i]);
}
}
// Create scene data. // Create scene data.
foreach (uint id in partitionIds) foreach (uint id in partitionIds)
{ {
ScenePartition p = scenePartitions[id]; ScenePartition p = scenePartitionData.scenePartitions[id];
data.AddRange(p.data); data.AddRange(p.data);
loadedScenePartitions.Add(p.id, p); scenePartitionData.loadedScenePartitions.Add(p.id, p);
} }
// Create scene. // Create scene.
@ -91,9 +94,10 @@ private void LoadScenePartitions(SortedSet<uint> partitionIds)
/// <summary> /// <summary>
/// Convert scene to partitions and save them to disk. /// Convert scene to partitions and save them to disk.
/// </summary> /// </summary>
public void SaveAll() public void Save()
{ {
if (!hasCreatedPartitions) return; if (!scenePartitionData.hasCreatedPartitions) return;
if (!scenePartitionData.hasLoadedPartitions) return;
DeleteLoadedPartitions(); // Delete the loaded partitions from disk so we can write the new ones. DeleteLoadedPartitions(); // Delete the loaded partitions from disk so we can write the new ones.
@ -140,23 +144,23 @@ public void Unload()
EditorSceneManager.SaveScene(scene); EditorSceneManager.SaveScene(scene);
scenePartitions.Clear(); scenePartitionData.scenePartitions.Clear();
AssetDatabase.Refresh(); AssetDatabase.Refresh();
} }
private void DeleteLoadedPartitions() private void DeleteLoadedPartitions()
{ {
if (!hasCreatedPartitions) return; if (!scenePartitionData.hasCreatedPartitions) return;
foreach (KeyValuePair<uint, ScenePartition> scenePartition in scenePartitions) foreach (KeyValuePair<uint, ScenePartition> scenePartition in scenePartitionData.scenePartitions)
{ {
if (!File.Exists(scenePartition.Value.filePath)) continue; if (!File.Exists(scenePartition.Value.filePath)) continue;
File.Delete(scenePartition.Value.filePath); File.Delete(scenePartition.Value.filePath);
} }
scenePartitions.Clear(); scenePartitionData.loadedScenePartitions.Clear();
} }
public void LoadPartitions(uint[] ids) public void LoadPartitions(uint[] ids)
@ -165,7 +169,7 @@ public void LoadPartitions(uint[] ids)
for (int i = 0; i < ids.Length; i++) for (int i = 0; i < ids.Length; i++)
{ {
SortedSet<uint> connections = ScenePartitionUtils.FindDeeplyLinkedObjects(scenePartitions, ids[i]); SortedSet<uint> connections = ScenePartitionUtils.FindDeeplyLinkedObjects(scenePartitionData.scenePartitions, ids[i]);
foreach (uint c in connections) foreach (uint c in connections)
{ {

View File

@ -34,11 +34,11 @@ public override void OnInspectorGUI()
scenePartitionSO.LoadAll(); scenePartitionSO.LoadAll();
} }
if (scenePartitionSO.hasCreatedPartitions) if (scenePartitionSO.scenePartitionData.hasCreatedPartitions)
{ {
if (GUILayout.Button("Save All")) if (GUILayout.Button("Save"))
{ {
scenePartitionSO.SaveAll(); scenePartitionSO.Save();
} }
} }
@ -58,50 +58,11 @@ public override void OnInspectorGUI()
id = EditorGUILayout.IntField("id", id); id = EditorGUILayout.IntField("id", id);
if (GUILayout.Button("Test Load")) if (GUILayout.Button("Load Section"))
{ {
scenePartitionSO.LoadPartitions(new uint[1] { (uint)id }); scenePartitionSO.LoadPartitions(new uint[1] { (uint)id });
} }
} }
EditorGUILayout.Space();
using (new EditorGUI.DisabledGroupScope(true))
{
if (scenePartitionSO.hasCreatedPartitions)
{
EditorGUILayout.LabelField($"scenePartitions");
foreach (System.Collections.Generic.KeyValuePair<uint, ScenePartition> scenePartition in scenePartitionSO.scenePartitions)
{
EditorGUILayout.IntField((int)scenePartition.Value.id);
EditorGUI.indentLevel++;
foreach (var reference in scenePartition.Value.references)
{
EditorGUILayout.IntField((int)reference);
}
EditorGUI.indentLevel--;
}
}
EditorGUILayout.Space();
if (scenePartitionSO.hasLoadedPartitions)
{
EditorGUILayout.LabelField($"loadedScenePartitions");
foreach (System.Collections.Generic.KeyValuePair<uint, ScenePartition> scenePartition in scenePartitionSO.loadedScenePartitions)
{
EditorGUILayout.IntField((int)scenePartition.Value.id);
EditorGUI.indentLevel++;
foreach (var reference in scenePartition.Value.references)
{
EditorGUILayout.IntField((int)reference);
}
EditorGUI.indentLevel--;
}
}
}
} }
} }
} }

View File

@ -0,0 +1,101 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace VertexColor.ScenePartition
{
[Serializable]
public class SerializableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, ISerializationCallbackReceiver
{
[SerializeField]
private List<TKey> keys = new List<TKey>();
[SerializeField]
private List<TValue> values = new List<TValue>();
public void OnBeforeSerialize()
{
keys.Clear();
values.Clear();
foreach (KeyValuePair<TKey, TValue> pair in this)
{
keys.Add(pair.Key);
values.Add(pair.Value);
}
}
public void OnAfterDeserialize()
{
Clear();
if (keys.Count != values.Count)
{
throw new Exception("Error: Key and value count does not match in the dictionary.");
}
for (int i = 0; i < keys.Count; i++)
{
Add(keys[i], values[i]);
}
}
}
[Serializable]
public class SerializableSortedList<TKey, TValue> : SortedList<TKey, TValue>, ISerializationCallbackReceiver
{
[SerializeField]
private List<TKey> keys = new List<TKey>();
[SerializeField]
private List<TValue> values = new List<TValue>();
public void OnBeforeSerialize()
{
keys.Clear();
values.Clear();
foreach (KeyValuePair<TKey, TValue> pair in this)
{
keys.Add(pair.Key);
values.Add(pair.Value);
}
}
public void OnAfterDeserialize()
{
Clear();
if (keys.Count != values.Count)
{
throw new Exception("Error: Key and value count does not match in the dictionary.");
}
for (int i = 0; i < keys.Count; i++)
{
Add(keys[i], values[i]);
}
}
}
[Serializable]
public class SerializableSortedSet<T> : SortedSet<T>, ISerializationCallbackReceiver
{
[SerializeField]
private List<T> elements = new List<T>();
public void OnBeforeSerialize()
{
elements.Clear();
elements.AddRange(this);
}
public void OnAfterDeserialize()
{
Clear();
for (int i = 0; i < elements.Count; i++)
{
Add(elements[i]);
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d20cd39f6cd10914188acde7ee871339
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: