projectEli/Assets/NeoFPS/Core/NeoSaveGames/Serialization/NeoSerializedScene.cs
2022-11-06 20:28:33 -05:00

323 lines
9.3 KiB
C#

using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace NeoSaveGames.Serialization
{
[ExecuteAlways]
[DisallowMultipleComponent]
public abstract class NeoSerializedScene : MonoBehaviour
{
[SerializeField, Tooltip("Prefabs available for serialization in this scene.")]
private NeoSerializedGameObject[] m_Prefabs = new NeoSerializedGameObject[0];
[SerializeField, Tooltip("Assets available for serialization in this scene.")]
private ScriptableObject[] m_Assets = new ScriptableObject[0];
[SerializeField]//, HideInInspector]
private NeoSerializedSceneObjectContainer m_SceneObjects = null;
private static List<NeoSerializedScene> s_ActiveScenes = new List<NeoSerializedScene>();
private Scene m_Scene = new Scene();
private int m_HashedPath = 0;
public Scene scene
{
get
{
if (!m_Scene.IsValid())
m_Scene = gameObject.scene;
return m_Scene;
}
}
public int hashedPath
{
get
{
if (m_HashedPath == 0)
m_HashedPath = NeoSerializationUtilities.StringToHash(scene.path);
return m_HashedPath;
}
}
public abstract bool isMainScene
{
get;
}
public NeoSerializedGameObject[] registeredPrefabs
{
get { return m_Prefabs; }
}
public ScriptableObject[] registeredAssets
{
get { return m_Assets; }
}
public NeoSerializedSceneObjectContainer sceneObjects
{
get { return m_SceneObjects; }
}
protected virtual void Awake()
{
if (Application.isPlaying)
{
s_ActiveScenes.Add(this);
// Assign child container
if (m_SceneObjects == null || !m_SceneObjects.isValid)
m_SceneObjects = new NeoSerializedSceneObjectContainer(this);
m_SceneObjects.Awake();
// Notify the save manager that the scene is loaded
SaveGameManager.NotifySceneLoaded(this);
}
}
protected virtual void Start()
{
//if (Application.isPlaying)
// SaveGameManager.RegisterScene(this);
}
protected virtual void OnDestroy()
{
if (Application.isPlaying)
{
s_ActiveScenes.Remove(this);
m_SceneObjects.OnDestroy();
SaveGameManager.UnregisterScene(this);
}
}
public static NeoSerializedScene GetByBuildIndex(int buildIndex)
{
for (int i = 0; i < s_ActiveScenes.Count; ++i)
{
if (s_ActiveScenes[i].scene.buildIndex == buildIndex)
return s_ActiveScenes[i];
}
return null;
}
public static NeoSerializedScene GetByName(string name)
{
for (int i = 0; i < s_ActiveScenes.Count; ++i)
{
if (s_ActiveScenes[i].scene.name == name)
return s_ActiveScenes[i];
}
return null;
}
public static NeoSerializedScene GetByPath(string path)
{
for (int i = 0; i < s_ActiveScenes.Count; ++i)
{
if (s_ActiveScenes[i].scene.path == path)
return s_ActiveScenes[i];
}
return null;
}
public static NeoSerializedScene GetByPathHash(int hash)
{
for (int i = 0; i < s_ActiveScenes.Count; ++i)
{
if (s_ActiveScenes[i].hashedPath == hash)
return s_ActiveScenes[i];
}
return null;
}
#if UNITY_EDITOR
public void RegisterPrefab(NeoSerializedGameObject prefab)
{
if (Array.IndexOf(m_Prefabs, prefab) == -1)
{
var so = new UnityEditor.SerializedObject(this);
var prop = so.FindProperty("m_Prefabs");
++prop.arraySize;
prop = prop.GetArrayElementAtIndex(prop.arraySize - 1);
prop.objectReferenceValue = prefab;
so.ApplyModifiedProperties();
}
}
#endif
#region VALIDATION
#if UNITY_EDITOR
private static List<GameObject> s_GatheredGameObjects = new List<GameObject>();
private static List<NeoSerializedGameObject> s_GatheredNsgos = new List<NeoSerializedGameObject>();
private void OnEnable()
{
if (!Application.isPlaying && gameObject.scene.IsValid())
{
UnityEditor.EditorApplication.hierarchyChanged += OnHierarchyChanged;
}
}
private void OnDisable()
{
if (!Application.isPlaying && gameObject.scene.IsValid())
{
UnityEditor.EditorApplication.hierarchyChanged -= OnHierarchyChanged;
}
}
void OnHierarchyChanged()
{
// Gather scene objects
scene.GetRootGameObjects(s_GatheredGameObjects);
for (int i = 0; i < s_GatheredGameObjects.Count; ++i)
{
var nsgo = s_GatheredGameObjects[i].GetComponent<NeoSerializedGameObject>();
if (nsgo != null)
s_GatheredNsgos.Add(nsgo);
}
// Validate container
if (m_SceneObjects.Validate(s_GatheredNsgos))
UnityEditor.SceneManagement.EditorSceneManager.MarkSceneDirty(scene);
s_GatheredGameObjects.Clear();
s_GatheredNsgos.Clear();
}
#endif
public virtual void OnValidate()
{
if (m_SceneObjects == null || m_SceneObjects.serializedScene == null)
m_SceneObjects = new NeoSerializedSceneObjectContainer(this);
ValidatePrefabs();
ValidateAssets();
}
void ValidatePrefabs()
{
int valid = 0;
for (int i = 0; i < m_Prefabs.Length; ++i)
{
if (m_Prefabs[i] != null)
++valid;
}
if (valid != m_Prefabs.Length)
{
var rebuilt = new NeoSerializedGameObject[valid];
int itr = 0;
for (int i = 0; i < m_Prefabs.Length; ++i)
{
if (m_Prefabs[i] != null)
{
rebuilt[itr] = m_Prefabs[i];
++itr;
}
}
m_Prefabs = rebuilt;
}
}
void ValidateAssets()
{
int valid = 0;
for (int i = 0; i < m_Assets.Length; ++i)
{
if (m_Assets[i] != null)
++valid;
}
if (valid != m_Assets.Length)
{
var rebuilt = new ScriptableObject[valid];
int itr = 0;
for (int i = 0; i < m_Assets.Length; ++i)
{
if (m_Assets[i] != null)
{
rebuilt[itr] = m_Assets[i];
++itr;
}
}
m_Assets = rebuilt;
}
}
#endregion
#region INSTANTIATION
public T InstantiatePrefab<T>(T prototype) where T : Component
{
return NeoSerializedObjectFactory.Instantiate(prototype, m_SceneObjects);
}
public T InstantiatePrefab<T>(T prototype, Vector3 position, Quaternion rotation) where T : Component
{
return NeoSerializedObjectFactory.Instantiate(prototype, m_SceneObjects, position, rotation);
}
public T InstantiatePrefab<T>(int prefabID, int serializationKey) where T : Component
{
var result = NeoSerializedObjectFactory.Instantiate(prefabID, serializationKey, m_SceneObjects);
if (result != null)
return result.GetComponent<T>();
else
return null;
}
#endregion
#region SERIALIZATION
public void WriteData(INeoSerializer writer)
{
WriteData(writer, SaveMode.Default);
}
public void WriteData(INeoSerializer writer, SaveMode saveMode)
{
if (!scene.IsValid())
return;
PreSaveScene();
m_SceneObjects.WriteGameObjects(writer, saveMode);
WriteProperties(writer);
PostSaveScene();
}
public void ReadData(INeoDeserializer reader)
{
PreLoadScene();
m_SceneObjects.ReadGameObjectHierarchy(reader);
m_SceneObjects.ReadGameObjectProperties(reader);
ReadProperties(reader);
PostLoadScene();
}
protected virtual void PreSaveScene() { }
protected virtual void PostSaveScene() { }
protected virtual void PreLoadScene() { }
protected virtual void PostLoadScene() { }
protected virtual void WriteProperties(INeoSerializer writer) { }
protected virtual void ReadProperties(INeoDeserializer reader) { }
#endregion
}
}