You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

960 lines
37 KiB
C#

4 years ago
using System;
using System.Collections;
using System.Collections.Generic;
#if UNITY_EDITOR
using UnityEditor.SceneManagement;
#endif
using UnityEngine;
#if PW_ADDRESSABLES
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.ResourceManagement.ResourceProviders;
#endif
using UnityEngine.Profiling;
using UnityEngine.SceneManagement;
namespace Gaia
{
[System.Serializable]
public enum LoadState { Loaded, Cached, Unloaded }
public enum ReferenceChange { AddImpostorReference, AddRegularReference, RemoveImpostorReference, RemoveRegularReference }
public class TerrainSceneActionQueueEntry { public TerrainScene m_terrainScene; public ReferenceChange m_referenceChange; public bool m_forced = false; public float m_distance = 0f; }
[System.Serializable]
public class TerrainScene
{
private List<GameObject> m_regularReferences = new List<GameObject>();
public List<GameObject> RegularReferences { get { return m_regularReferences; } }
private List<GameObject> m_impostorReferences = new List<GameObject>();
public List<GameObject> ImpostorReferences { get { return m_impostorReferences; } }
public Vector3Double m_pos;
public Vector3Double m_currentOriginOffset;
public BoundsDouble m_bounds;
public string m_scenePath;
public string m_impostorScenePath;
public string m_backupScenePath;
public string m_colliderScenePath;
public LoadState m_regularLoadState;
public LoadState m_impostorLoadState;
public bool m_useFloatingPointFix;
public long m_nextUpdateTimestamp;
private AsyncOperation asyncLoadOp;
public bool m_regularLoadRequested;
public bool m_regularUnloadRequested;
public bool m_impostorLoadRequested;
public bool m_impostorUnloadRequested;
private long m_loadCacheTreshold = 4294967296;
private bool m_forceSceneRemove = false;
private List<GameObject> m_rootGameObjects = new List<GameObject>();
public bool m_isFoldedOut;
private GameObject m_terrainObj;
public long m_regularCachedTimestamp;
public long m_impostorCachedTimestamp;
public bool m_stitchedWestBorder;
public bool m_stitchedEastBorder;
public bool m_stitchedSouthBorder;
public bool m_stitchedNorthBorder;
#if UNITY_EDITOR
public GameObject TerrainObj { get => m_terrainObj; }
#endif
public string GetTerrainName(string path = "")
{
if (path == "")
{
path = m_scenePath;
}
if (path.LastIndexOf("Terrain") >= 0)
{
return path.Substring(path.LastIndexOf("Terrain")).Replace(".unity", "");
}
else
{
Debug.LogError($"Could not get the Terrain Name for the following path '{m_scenePath}'.");
return "";
}
}
public string GetImpostorName(string path = "")
{
if (path == "")
{
path = m_impostorScenePath;
}
if (path.LastIndexOf("Impostor") >= 0)
{
return path.Substring(path.LastIndexOf("Impostor")).Replace(".unity", "");
}
else
{
Debug.LogError($"Could not get the Impostor Name for the following path '{m_impostorScenePath}'.");
return "";
}
}
public void RemoveAllReferences(bool forceSceneRemove = false)
{
m_regularReferences.Clear();
m_impostorReferences.Clear();
#if GAIA_PRO_PRESENT
m_regularLoadRequested = false;
m_regularUnloadRequested = false;
m_impostorLoadRequested = false;
m_impostorUnloadRequested = false;
m_forceSceneRemove = forceSceneRemove;
UpdateLoadState(m_regularReferences, ref m_regularLoadState, ref m_regularLoadRequested, ref m_regularUnloadRequested, false);
UpdateLoadState(m_impostorReferences, ref m_impostorLoadState, ref m_impostorLoadRequested, ref m_impostorUnloadRequested, true);
#endif
}
public void RemoveAllImpostorReferences(bool forceSceneRemove = false)
{
m_impostorReferences.Clear();
#if GAIA_PRO_PRESENT
m_impostorLoadRequested = false;
m_impostorUnloadRequested = false;
m_forceSceneRemove = forceSceneRemove;
UpdateLoadState(m_impostorReferences, ref m_impostorLoadState, ref m_impostorLoadRequested, ref m_impostorUnloadRequested, true);
#endif
}
public void RemoveAllRegularReferences(bool forceSceneRemove = false)
{
m_regularReferences.Clear();
#if GAIA_PRO_PRESENT
m_regularLoadRequested = false;
m_regularUnloadRequested = false;
m_forceSceneRemove = forceSceneRemove;
UpdateLoadState(m_regularReferences, ref m_regularLoadState, ref m_regularLoadRequested, ref m_regularUnloadRequested, true);
#endif
}
public void AddRegularReference(GameObject gameObject)
{
if (!m_regularReferences.Contains(gameObject))
{
m_forceSceneRemove = false;
m_regularReferences.Add(gameObject);
}
UpdateLoadState(m_regularReferences, ref m_regularLoadState, ref m_regularLoadRequested, ref m_regularUnloadRequested, false);
}
public void RemoveRegularReference(GameObject gameObject, long cacheSize = 0, bool forceSceneRemove = false)
{
m_forceSceneRemove = forceSceneRemove;
if (m_regularReferences.Contains(gameObject))
{
m_regularReferences.Remove(gameObject);
}
if (cacheSize != 0)
{
m_loadCacheTreshold = cacheSize;
}
UpdateLoadState(m_regularReferences, ref m_regularLoadState, ref m_regularLoadRequested, ref m_regularUnloadRequested, false);
}
public bool HasRegularReference(GameObject gameObject)
{
return m_regularReferences.Contains(gameObject);
}
public void AddImpostorReference(GameObject gameObject)
{
if (!String.IsNullOrEmpty(m_impostorScenePath))
{
if (!m_impostorReferences.Contains(gameObject))
{
m_forceSceneRemove = false;
m_impostorReferences.Add(gameObject);
}
UpdateLoadState(m_impostorReferences, ref m_impostorLoadState, ref m_impostorLoadRequested, ref m_impostorUnloadRequested, true);
}
}
public void RemoveImpostorReference(GameObject gameObject, long cacheSize = 0, bool forceSceneRemove = false)
{
if (!String.IsNullOrEmpty(m_impostorScenePath))
{
m_forceSceneRemove = forceSceneRemove;
if (m_impostorReferences.Contains(gameObject))
{
m_impostorReferences.Remove(gameObject);
}
if (cacheSize != 0)
{
m_loadCacheTreshold = cacheSize;
}
UpdateLoadState(m_impostorReferences, ref m_impostorLoadState, ref m_impostorLoadRequested, ref m_impostorUnloadRequested, true);
}
}
public bool HasImpostorReference(GameObject gameObject)
{
return m_impostorReferences.Contains(gameObject);
}
public void UpdateLoadState(List<GameObject> referenceList, ref LoadState loadState, ref bool loadRequested, ref bool unLoadRequested, bool isImpostor)
{
string scenePath = m_scenePath;
if (isImpostor)
{
scenePath = m_impostorScenePath;
}
if (TerrainLoaderManager.ColliderOnlyLoadingActive)
{
scenePath = m_colliderScenePath;
}
#if GAIA_PRO_PRESENT
if (scenePath == null)
{
return;
}
//sanity check on the references: does the GO still exist?
CheckForRelevance(referenceList);
//locked - no state change for now, used when the loader is dragged around in the scene, etc.
#if UNITY_EDITOR
Scene scene = EditorSceneManager.GetSceneByPath(scenePath);
#else
Scene scene = SceneManager.GetSceneByPath(scenePath);
#endif
SyncLoadState(scene, ref loadState, ref loadRequested, ref unLoadRequested, isImpostor);
switch (loadState)
{
case LoadState.Loaded:
if (referenceList.Count <= 0 && scene.isLoaded)
{
UnloadScene(scene, ref loadRequested, ref unLoadRequested, ref loadState, isImpostor);
//if a regular terrain was just unloaded, do an update on the impostor to see if it needs to be loaded in
if (!isImpostor && !String.IsNullOrEmpty(m_impostorScenePath))
{
UpdateLoadState(m_impostorReferences, ref m_impostorLoadState, ref m_impostorLoadRequested, ref m_impostorUnloadRequested, true);
}
}
if (referenceList.Count >= 1)
{
//Is this a regular scene and the Impostor is still loaded? Remove it!
if (!isImpostor && m_impostorLoadState == LoadState.Loaded)
{
ReplaceImpostor();
}
}
break;
case LoadState.Cached:
if (referenceList.Count >= 1 && scene.isLoaded)
{
//do not need to activate the cached scene if this is an imposter and the regular scene has references and is loaded in already
if (isImpostor && m_regularReferences.Count >= 1 && m_regularLoadState == LoadState.Loaded)
{
break;
}
foreach (GameObject go in scene.GetRootGameObjects())
{
go.SetActive(true);
Terrain terrain = go.GetComponent<Terrain>();
if (terrain != null)
{
//rwactivate terrain / trees in case if culled
terrain.drawTreesAndFoliage = true;
terrain.drawHeightmap = true;
m_terrainObj = go;
CheckForStitching(terrain);
#if FLORA_PRESENT
//Wake up the flora detail objects, if any
foreach (ProceduralWorlds.Flora.DetailObject detailObject in terrain.transform.GetComponentsInChildren<ProceduralWorlds.Flora.DetailObject>())
{
detailObject.RefreshAll();
}
#endif
}
}
//Is this a regular scene that just came out of cache and the Impostor is still loaded? Remove it!
if (!isImpostor && m_impostorLoadState == LoadState.Loaded)
{
ReplaceImpostor();
}
loadState = LoadState.Loaded;
}
//we still need to process force removal requests
if (referenceList.Count <= 0 && scene.isLoaded && m_forceSceneRemove)
{
UnloadScene(scene, ref loadRequested, ref unLoadRequested, ref loadState, isImpostor);
}
break;
case LoadState.Unloaded:
if (referenceList.Count >= 1 && !scene.isLoaded)
{
//do not need to load if this is an imposter and the regular scene has references and is loaded in already anyways
if (isImpostor && m_regularReferences.Count >= 1 && m_regularLoadState == LoadState.Loaded)
{
break;
}
LoadScene(scene, ref loadRequested, ref loadState, isImpostor);
}
break;
}
#if UNITY_EDITOR
scene = EditorSceneManager.GetSceneByPath(scenePath);
#else
scene = SceneManager.GetSceneByPath(scenePath);
#endif
SyncLoadState(scene, ref loadState, ref loadRequested, ref unLoadRequested, isImpostor);
#endif
}
/// <summary>
/// Tries to get the x and z coordinate for a terrain scene from its filename (assuming it follows the gaia naming scheme)
/// </summary>
/// <param name="fileName">The filename to get the coordinates from</param>
/// <param name="xCoord">int to store the x Coordinate in</param>
/// <param name="zCoord">int to store the z Coordinate in</param>
/// <returns></returns>
public static bool GetCoords(string fileName, ref int xCoord, ref int zCoord)
{
string firstSegment = fileName.Split('-')[0];
xCoord = -99;
zCoord = -99;
bool successX, successZ;
try
{
successX = Int32.TryParse(firstSegment.Substring(firstSegment.IndexOf('_') + 1, firstSegment.LastIndexOf('_') - (firstSegment.IndexOf('_') + 1)), out xCoord);
successZ = Int32.TryParse(firstSegment.Substring(firstSegment.LastIndexOf('_') + 1, firstSegment.Length - 1 - firstSegment.LastIndexOf('_')), out zCoord);
}
catch (Exception ex)
{
if (ex.Message == "123")
{
}
successX = false;
successZ = false;
}
return successX & successZ;
}
/// <summary>
/// Synchronizes the load state of the unity scene object with Gaias terrain scene. There are edge cases where those two can get out of sync, e.g. race conditions, users opening
/// and closing scenes manually etc. so it can be required to compare the load state of the two object types.
/// </summary>
/// <param name="scene"></param>
private void SyncLoadState(Scene scene, ref LoadState loadState, ref bool loadRequested, ref bool unLoadRequested, bool isImpostor)
{
if (scene.isLoaded)
{
bool isCached = true;
foreach (GameObject go in scene.GetRootGameObjects())
{
if (go.activeInHierarchy)
{
isCached = false;
}
}
if (isCached)
{
if (loadState != LoadState.Cached)
{
//Here we discover by syncing the load state that the terrain is actually cached, so we need to update the timestamp.
if (isImpostor)
{
m_impostorCachedTimestamp = GaiaUtils.GetUnixTimestamp();
}
else
{
m_regularCachedTimestamp = GaiaUtils.GetUnixTimestamp();
}
}
loadState = LoadState.Cached;
}
else
{
loadState = LoadState.Loaded;
}
loadRequested = false;
}
else
{
loadState = LoadState.Unloaded;
unLoadRequested = false;
}
}
private void LoadScene(Scene scene, ref bool loadRequested, ref LoadState loadState, bool isImpostor)
{
string scenePath = m_scenePath;
if (isImpostor)
{
scenePath = m_impostorScenePath;
}
if (TerrainLoaderManager.ColliderOnlyLoadingActive)
{
scenePath = m_colliderScenePath;
}
#if UNITY_EDITOR
if (Application.isPlaying)
{
if (!loadRequested)
{
TerrainLoaderManager tlm = TerrainLoaderManager.Instance;
long currentTimeStamp = GaiaUtils.GetUnixTimestamp();
//don't load if the loading treshold has not passed yet
//this is to prevent a bottleneck from loading too many terrains at the same time
if (tlm.m_lastTerrainLoadedTimeStamp + tlm.m_terrainLoadingTresholdMS > currentTimeStamp)
{
return;
}
if (tlm.TerrainSceneStorage.m_useAddressables)
{
#if PW_ADDRESSABLES
LoadAddressableSceneAsync(isImpostor);
#endif
}
else
{
asyncLoadOp = SceneManager.LoadSceneAsync(scenePath, LoadSceneMode.Additive);
tlm.m_lastTerrainLoadedTimeStamp = currentTimeStamp;
if (isImpostor)
{
asyncLoadOp.completed += SceneLoadCompletedImpostor;
}
else
{
asyncLoadOp.completed += SceneLoadCompletedRegular;
}
}
loadRequested = true;
}
}
else
{
if (!TerrainLoaderManager.Instance.m_assembliesAreReloading)
{
try
{
ProgressBar.Show(ProgressBarPriority.TerrainLoading, "Loading Terrain", "Loading Terrain...", 0, 0, false, false);
EditorSceneManager.sceneOpened += SceneOpened;
EditorSceneManager.OpenScene(scenePath, OpenSceneMode.Additive);
ProgressBar.Clear(ProgressBarPriority.TerrainLoading);
}
catch (Exception ex)
{
if (ex != null)
{
//just to shut up the warning
}
//Make sure the Terrain Loader Manager is subscribed to the assembly loading events
TerrainLoaderManager.Instance.SubscribeToAssemblyReloadEvents();
}
}
}
#else
if (!loadRequested)
{
TerrainLoaderManager tlm = TerrainLoaderManager.Instance;
long currentTimeStamp = GaiaUtils.GetUnixTimestamp();
//don't load if the loading treshold has not passed yet
//this is to prevent a bottleneck from loading too many terrains at the same time
if (tlm.m_lastTerrainLoadedTimeStamp + tlm.m_terrainLoadingTresholdMS > currentTimeStamp)
{
return;
}
tlm.m_lastTerrainLoadedTimeStamp = currentTimeStamp;
if (tlm.TerrainSceneStorage.m_useAddressables)
{
#if PW_ADDRESSABLES
LoadAddressableSceneAsync(isImpostor);
#endif
}
else {
asyncLoadOp = SceneManager.LoadSceneAsync(scenePath, LoadSceneMode.Additive);
if (isImpostor)
{
asyncLoadOp.completed += SceneLoadCompletedImpostor;
}
else
{
asyncLoadOp.completed += SceneLoadCompletedRegular;
}
}
loadRequested = true;
}
#endif
}
#if PW_ADDRESSABLES
private void LoadAddressableSceneAsync(bool isImpostor)
{
if (isImpostor)
{
Addressables.GetDownloadSizeAsync(m_impostorScenePath).Completed += AddressableImpostorDownloadSizeCompleted;
if (TerrainLoaderManager.Instance.TerrainSceneStorage.m_preloadAddressablesWithImpostors)
{
Addressables.GetDownloadSizeAsync(m_scenePath).Completed += AddressableRegularDownloadSizeCompletedPreload;
}
}
else
{
//Check the download size, continue from there
Addressables.GetDownloadSizeAsync(m_scenePath).Completed += AddressableRegularDownloadSizeCompleted;
}
}
private void AddressableRegularDownloadSizeCompletedPreload(AsyncOperationHandle<long> obj)
{
//If the download size is greater than 0, download all the dependencies.
if (obj.Result > 0)
{
Addressables.DownloadDependenciesAsync(m_scenePath).Completed += AddressableDownloadCompletedRegularPreload;
}
}
private void AddressableRegularDownloadSizeCompleted(AsyncOperationHandle<long> obj)
{
//If the download size is greater than 0, download all the dependencies.
if (obj.Result > 0)
{
Addressables.DownloadDependenciesAsync(m_scenePath).Completed += AddressableDownloadCompletedRegular;
}
else
{
Addressables.LoadSceneAsync(m_scenePath, LoadSceneMode.Additive).Completed += AddressableLoadCompletedRegular;
}
}
private void AddressableImpostorDownloadSizeCompleted(AsyncOperationHandle<long> obj)
{
//If the download size is greater than 0, download all the dependencies.
if (obj.Result > 0)
{
Addressables.DownloadDependenciesAsync(m_impostorScenePath).Completed += AddressableDownloadCompletedImpostor;
}
else
{
Addressables.LoadSceneAsync(m_impostorScenePath, LoadSceneMode.Additive).Completed += AddressableLoadCompletedImpostor;
}
}
private void AddressableDownloadCompletedRegular(AsyncOperationHandle obj)
{
Addressables.LoadSceneAsync(m_scenePath, LoadSceneMode.Additive).Completed += AddressableLoadCompletedRegular;
}
private void AddressableDownloadCompletedRegularPreload(AsyncOperationHandle obj)
{
}
private void AddressableDownloadCompletedImpostor(AsyncOperationHandle obj)
{
Addressables.LoadSceneAsync(m_impostorScenePath, LoadSceneMode.Additive).Completed += AddressableLoadCompletedImpostor;
}
#endif
/// <summary>
/// Will update the load state of the terrain scene for all scene types - regular, collider, impostor, with the data that is currently stored in the terrain scene.
/// </summary>
public void UpdateWithCurrentData()
{
UpdateLoadState(m_regularReferences, ref m_regularLoadState, ref m_regularLoadRequested, ref m_regularUnloadRequested, false);
UpdateLoadState(m_impostorReferences, ref m_impostorLoadState, ref m_impostorLoadRequested, ref m_impostorUnloadRequested, true);
}
private void UnloadScene(Scene scene, ref bool loadRequested, ref bool unLoadRequested, ref LoadState loadState, bool isImpostor, bool bypassTreshold = false)
{
if (Application.isPlaying)
{
TerrainLoaderManager tlm = TerrainLoaderManager.Instance;
long currentTimeStamp = GaiaUtils.GetUnixTimestamp();
//don't unload if the loading treshold has not passed yet
//this is to prevent a bottleneck from loading too many terrains at the same time
if (tlm.m_lastTerrainLoadedTimeStamp + tlm.m_terrainLoadingTresholdMS > currentTimeStamp && !bypassTreshold)
{
return;
}
tlm.m_lastTerrainLoadedTimeStamp = currentTimeStamp;
}
//Make sure that loading again is allowed
loadRequested = false;
//If this is not a request to unload an impostor, but the scene would have one that is referenced, we must not unload this scene until the impostor scene is loaded in.
if (!isImpostor && !String.IsNullOrEmpty(m_impostorScenePath) && m_impostorReferences.Count >= 1 && m_impostorLoadState != LoadState.Loaded)
{
//Force an update on the impostor, since it should be able to load in now with the regular scene having no references anymore.
UpdateLoadState(m_impostorReferences, ref m_impostorLoadState, ref m_impostorLoadRequested, ref m_impostorUnloadRequested, true);
return;
}
if (Profiler.GetTotalReservedMemoryLong() < m_loadCacheTreshold && !m_forceSceneRemove && TerrainLoaderManager.Instance.CachingAllowed())
{
//only deactivate the root game objects first, actual unload will happen later
foreach (GameObject go in scene.GetRootGameObjects())
{
go.SetActive(false);
}
#if UNITY_EDITOR
if (!Application.isPlaying)
{
if (scene.isDirty)
{
EditorSceneManager.SaveScene(scene);
}
}
#endif
unLoadRequested = false;
loadState = LoadState.Cached;
if (isImpostor)
{
m_impostorCachedTimestamp = GaiaUtils.GetUnixTimestamp();
}
else
{
m_regularCachedTimestamp = GaiaUtils.GetUnixTimestamp();
}
}
else
{
//conditions for caching not met, do full unload now
if (Application.isPlaying)
{
if (!unLoadRequested)
{
SceneManager.UnloadSceneAsync(scene.name);
loadState = LoadState.Unloaded;
unLoadRequested = true;
}
}
else
{
#if UNITY_EDITOR
ProgressBar.Show(ProgressBarPriority.TerrainLoading, "Unloading Terrain", "Unloading Terrain...", 0, 0, false, false);
if (scene.isDirty)
{
EditorSceneManager.SaveScene(scene);
}
EditorSceneManager.CloseScene(scene, true);
//TerrainLoaderManager.Instance.EmptyCache();
ProgressBar.Clear(ProgressBarPriority.TerrainLoading);
loadState = LoadState.Unloaded;
unLoadRequested = false;
#endif
}
}
}
private void CheckForRelevance(List<GameObject> referenceList)
{
#if GAIA_PRO_PRESENT
for (int i = referenceList.Count - 1; i >= 0; i--)
{
if (referenceList[i] == null)
{
referenceList.RemoveAt(i);
}
else
{
//Is it still relevant?
TerrainLoader loader = referenceList[i].GetComponent<TerrainLoader>();
if (loader != null)
{
if (!loader.enabled || !loader.gameObject.activeInHierarchy || loader.LoadMode == LoadMode.Disabled || (!loader.m_isSelected && loader.LoadMode == LoadMode.EditorSelected))
{
referenceList.RemoveAt(i);
}
}
}
}
#endif
}
#if UNITY_EDITOR
private void SceneOpened(Scene scene, OpenSceneMode mode)
{
if (m_scenePath == null)
{
return;
}
//there is an edge case when the scene opened event is fired but the scene is still not loaded
if (scene.isLoaded == false)
{
if (scene.path == m_scenePath || scene.path == m_colliderScenePath)
{
m_regularLoadState = LoadState.Unloaded;
}
if (scene.path == m_impostorScenePath)
{
m_impostorLoadState = LoadState.Unloaded;
}
return;
}
if (scene.path == m_scenePath || scene.path == m_colliderScenePath)
{
if (m_regularLoadState != LoadState.Loaded)
{
Terrain terrain = null;
foreach (GameObject go in scene.GetRootGameObjects())
{
terrain = go.GetComponent<Terrain>();
if (terrain != null)
{
m_terrainObj = go;
go.transform.position = m_bounds.center - m_currentOriginOffset - new Vector3Double(m_bounds.size.x / 2f, 0f, m_bounds.size.z / 2f);
}
go.SetActive(true);
}
m_regularLoadState = LoadState.Loaded;
ReplaceImpostor();
if (terrain != null)
{
CheckForStitching(terrain);
}
}
EditorSceneManager.sceneOpened -= SceneOpened;
}
if (scene.path == m_impostorScenePath)
{
if (m_impostorLoadState != LoadState.Loaded)
{
foreach (GameObject go in scene.GetRootGameObjects())
{
go.SetActive(true);
}
m_impostorLoadState = LoadState.Loaded;
//Make sure the regular scene has not been loaded in the meantime due to a race condition. If it has, remove the impostor right away.
if (m_regularReferences.Count >= 1 && m_regularLoadState == LoadState.Loaded)
{
ReplaceImpostor();
}
}
EditorSceneManager.sceneOpened -= SceneOpened;
}
}
#endif
#if PW_ADDRESSABLES
private void AddressableLoadCompletedRegular(AsyncOperationHandle<SceneInstance> obj)
{
SceneLoadCompletedHandling();
obj.Completed -= AddressableLoadCompletedRegular;
}
private void AddressableLoadCompletedImpostor(AsyncOperationHandle<SceneInstance> obj)
{
ImpostorLoadCompletedHandling();
obj.Completed -= AddressableLoadCompletedImpostor;
}
#endif
private void SceneLoadCompletedRegular(AsyncOperation obj)
{
SceneLoadCompletedHandling();
obj.completed -= SceneLoadCompletedRegular;
}
private void SceneLoadCompletedImpostor(AsyncOperation obj)
{
obj.completed -= SceneLoadCompletedImpostor;
}
private void SceneLoadCompletedHandling()
{
#if GAIA_PRO_PRESENT
string scenePath = m_scenePath;
Terrain terrain = null;
if (TerrainLoaderManager.ColliderOnlyLoadingActive)
{
scenePath = m_colliderScenePath;
}
Scene scene = SceneManager.GetSceneByPath(scenePath);
if (!scene.isLoaded)
{
return;
}
foreach (GameObject go in scene.GetRootGameObjects())
{
if (m_useFloatingPointFix)
{
go.transform.position += FloatingPointFix.Instance.totalOffset;
if (go.transform.GetComponent<FloatingPointFixMember>() == null)
{
go.AddComponent<FloatingPointFixMember>();
}
}
terrain = go.GetComponent<Terrain>();
if (terrain != null)
{
m_terrainObj = go;
}
go.SetActive(true);
}
m_regularLoadState = LoadState.Loaded;
ReplaceImpostor();
if (terrain != null)
{
CheckForStitching(terrain);
}
#endif
}
private void ImpostorLoadCompletedHandling()
{
#if GAIA_PRO_PRESENT
Scene scene = SceneManager.GetSceneByPath(m_impostorScenePath);
foreach (GameObject go in scene.GetRootGameObjects())
{
if (m_useFloatingPointFix)
{
go.transform.position += FloatingPointFix.Instance.totalOffset;
if (go.transform.GetComponent<FloatingPointFixMember>() == null)
{
go.AddComponent<FloatingPointFixMember>();
}
}
go.SetActive(true);
}
m_impostorLoadState = LoadState.Loaded;
//Make sure the regular scene has not been loaded in the meantime due to a race condition. If it has, remove the impostor right away.
if (m_regularReferences.Count >= 1 && m_regularLoadState == LoadState.Loaded)
{
ReplaceImpostor();
}
#endif
}
private void CheckForStitching(Terrain terrain)
{
if (!m_stitchedEastBorder || !m_stitchedWestBorder || !m_stitchedNorthBorder || !m_stitchedSouthBorder)
{
ShiftLoadedTerrain();
}
if (m_stitchedEastBorder == false)
{
TerrainHelper.TryStitch(terrain, StitchDirection.East);
}
if (m_stitchedWestBorder == false)
{
TerrainHelper.TryStitch(terrain, StitchDirection.West);
}
if (m_stitchedNorthBorder == false)
{
TerrainHelper.TryStitch(terrain, StitchDirection.North);
}
if (m_stitchedSouthBorder == false)
{
TerrainHelper.TryStitch(terrain, StitchDirection.South);
}
}
private void ReplaceImpostor()
{
#if GAIA_PRO_PRESENT
if (!String.IsNullOrEmpty(m_impostorScenePath) && m_impostorLoadState == LoadState.Loaded)
{
#if UNITY_EDITOR
Scene impostorScene = EditorSceneManager.GetSceneByPath(m_impostorScenePath);
#else
Scene impostorScene = SceneManager.GetSceneByPath(m_impostorScenePath);
#endif
UnloadScene(impostorScene, ref m_impostorLoadRequested, ref m_impostorUnloadRequested, ref m_impostorLoadState, true, true);
}
#endif
}
public void ShiftLoadedTerrain()
{
//Perform the shift for both loaded and cached terrains
if (m_regularLoadState == LoadState.Loaded || m_regularLoadState == LoadState.Cached)
{
string scenePath = m_scenePath;
if (TerrainLoaderManager.ColliderOnlyLoadingActive)
{
scenePath = m_colliderScenePath;
}
#if UNITY_EDITOR
Scene scene = EditorSceneManager.GetSceneByPath(scenePath);
#else
Scene scene = SceneManager.GetSceneByPath(m_scenePath);
#endif
if (scene.isLoaded)
{
scene.GetRootGameObjects(m_rootGameObjects);
foreach (GameObject go in m_rootGameObjects)
{
go.transform.position = m_bounds.center - m_currentOriginOffset - new Vector3Double(m_bounds.size.x / 2f, 0f, m_bounds.size.z / 2f);
}
}
else
{
m_regularLoadState = LoadState.Unloaded;
}
}
if (m_impostorLoadState == LoadState.Loaded || m_impostorLoadState == LoadState.Cached)
{
#if UNITY_EDITOR
Scene scene = EditorSceneManager.GetSceneByPath(m_impostorScenePath);
#else
Scene scene = SceneManager.GetSceneByPath(m_impostorScenePath);
#endif
if (scene.isLoaded)
{
scene.GetRootGameObjects(m_rootGameObjects);
foreach (GameObject go in m_rootGameObjects)
{
go.transform.position = m_bounds.center - m_currentOriginOffset - new Vector3Double(m_bounds.size.x / 2f, 0f, m_bounds.size.z / 2f);
}
}
else
{
m_impostorLoadState = LoadState.Unloaded;
}
}
}
}
}