333 lines
11 KiB
C#
333 lines
11 KiB
C#
using System;
|
|
using System.Collections;
|
|
using UnityEngine;
|
|
using UnityEngine.SceneManagement;
|
|
using OctoCore.Navigation.Data;
|
|
|
|
#if OCTO_ADDRESSABLES
|
|
using UnityEngine.AddressableAssets;
|
|
using UnityEngine.ResourceManagement.AsyncOperations;
|
|
using UnityEngine.ResourceManagement.ResourceProviders;
|
|
#endif
|
|
|
|
namespace OctoCore.Navigation
|
|
{
|
|
/// <summary>
|
|
/// Scene management module.
|
|
/// Handles scene loading, transitions, and teleportation.
|
|
/// </summary>
|
|
[System.Serializable]
|
|
public class OctoNavigation : IOctoModule
|
|
{
|
|
/// <summary>
|
|
/// Currently loaded scene data.
|
|
/// </summary>
|
|
[OctoReadOnly] public OctoSceneData CurrentScene;
|
|
|
|
/// <summary>
|
|
/// Pending teleporter between scene changes (non-null only during scene transitions).
|
|
/// </summary>
|
|
[OctoReadOnly] public OctoTeleporterData PendingTeleporter;
|
|
|
|
/// <summary>
|
|
/// Invoked when scene loading starts.
|
|
/// </summary>
|
|
public Action<OctoSceneData> OnSceneLoadStarted;
|
|
|
|
/// <summary>
|
|
/// Invoked when scene loading completes.
|
|
/// </summary>
|
|
public Action<OctoSceneData> OnSceneLoadCompleted;
|
|
|
|
/// <summary>
|
|
/// Invoked when teleport starts.
|
|
/// </summary>
|
|
public Action<OctoTeleporterData, OctoTeleporterData> OnTeleportStarted;
|
|
|
|
/// <summary>
|
|
/// Invoked when teleport completes.
|
|
/// </summary>
|
|
public Action<OctoTeleporterData, OctoTeleporterData> OnTeleportCompleted;
|
|
|
|
private Coroutine _loadingCoroutine;
|
|
private OctoSceneFade _fadeCanvas;
|
|
private bool _setPlayerRotation;
|
|
|
|
public void Init(OctoSettings settings)
|
|
{
|
|
// Find current scene in settings
|
|
string currentSceneName = SceneManager.GetActiveScene().name;
|
|
foreach (var sceneData in settings.Scenes.SceneDatas)
|
|
{
|
|
if (sceneData.SceneName == currentSceneName)
|
|
{
|
|
CurrentScene = sceneData;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Create fade canvas
|
|
CreateFadeCanvas();
|
|
|
|
if (OctoEvents.Instance)
|
|
OctoEvents.Instance.SetScenesInitialized();
|
|
|
|
if (OctoCore.Instance.Development.Log)
|
|
Debug.Log($"[OctoNavigation] Initialized (Addressables: {settings.Scenes.UseAddressables})");
|
|
}
|
|
|
|
public void Tick() { }
|
|
|
|
public void OnSceneChanged(Scene current, Scene next)
|
|
{
|
|
// Update CurrentScene reference
|
|
if (OctoCore.Instance && OctoCore.Instance.Settings)
|
|
{
|
|
foreach (var sceneData in OctoCore.Instance.Settings.Scenes.SceneDatas)
|
|
{
|
|
if (sceneData.SceneName == next.name)
|
|
{
|
|
CurrentScene = sceneData;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void OnQuit() { }
|
|
|
|
/// <summary>
|
|
/// Load a scene using OctoSceneData.
|
|
/// </summary>
|
|
public void LoadScene(OctoSceneData sceneData)
|
|
{
|
|
if (sceneData == null)
|
|
{
|
|
Debug.LogError("[OctoNavigation] SceneData is null");
|
|
return;
|
|
}
|
|
|
|
_loadingCoroutine = OctoCore.Instance.StartCoroutine(LoadSceneCoroutine(sceneData));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Teleport using OctoTeleporterData.
|
|
/// </summary>
|
|
public void Teleport(OctoTeleporterData teleporter)
|
|
{
|
|
if (teleporter == null)
|
|
{
|
|
Debug.LogError("[OctoNavigation] Teleporter is null");
|
|
return;
|
|
}
|
|
|
|
OnTeleportStarted?.Invoke(null, teleporter);
|
|
|
|
// Same scene teleport
|
|
if (teleporter.TargetScene == null ||
|
|
teleporter.TargetScene == CurrentScene)
|
|
{
|
|
OctoCore.Instance.StartCoroutine(TeleportSameSceneCoroutine(teleporter));
|
|
}
|
|
// Different scene teleport
|
|
else
|
|
{
|
|
OctoCore.Instance.StartCoroutine(TeleportDifferentSceneCoroutine(teleporter));
|
|
}
|
|
}
|
|
|
|
private IEnumerator LoadSceneCoroutine(OctoSceneData sceneData)
|
|
{
|
|
OnSceneLoadStarted?.Invoke(sceneData);
|
|
|
|
// Get global fade settings
|
|
OctoSettings.ScenesSettings.FadeTransitionSettings fadeSettings = OctoCore.Instance.Settings.Scenes.FadeSettings;
|
|
|
|
// Fade out
|
|
if (sceneData.UseFadeTransition && _fadeCanvas)
|
|
{
|
|
_fadeCanvas.FadeOut(fadeSettings.FadeOutDuration, fadeSettings.FadeColor);
|
|
yield return new WaitForSeconds(fadeSettings.FadeOutDuration);
|
|
}
|
|
|
|
// Check if using Addressables
|
|
bool useAddressables = OctoCore.Instance.Settings.Scenes.UseAddressables;
|
|
|
|
#if OCTO_ADDRESSABLES
|
|
if (useAddressables)
|
|
{
|
|
yield return LoadSceneAddressables(sceneData);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
yield return LoadSceneStandard(sceneData);
|
|
}
|
|
|
|
// Fade in
|
|
if (sceneData.UseFadeTransition && _fadeCanvas)
|
|
{
|
|
_fadeCanvas.FadeIn(fadeSettings.FadeInDuration);
|
|
yield return new WaitForSeconds(fadeSettings.FadeInDuration);
|
|
}
|
|
|
|
OnSceneLoadCompleted?.Invoke(sceneData);
|
|
|
|
if (OctoCore.Instance.Development.Log)
|
|
Debug.Log($"[OctoNavigation] Scene loaded: {sceneData.SceneName}");
|
|
}
|
|
|
|
private IEnumerator LoadSceneStandard(OctoSceneData sceneData)
|
|
{
|
|
AsyncOperation asyncLoad = SceneManager.LoadSceneAsync(sceneData.SceneName);
|
|
yield return asyncLoad;
|
|
}
|
|
|
|
#if OCTO_ADDRESSABLES
|
|
private IEnumerator LoadSceneAddressables(OctoSceneData sceneData)
|
|
{
|
|
AsyncOperationHandle<SceneInstance> handle = Addressables.LoadSceneAsync(sceneData.SceneName, LoadSceneMode.Single);
|
|
yield return handle;
|
|
|
|
if (handle.Status != AsyncOperationStatus.Succeeded)
|
|
{
|
|
Debug.LogError($"[OctoNavigation] Failed to load scene: {sceneData.SceneName}");
|
|
}
|
|
}
|
|
#endif
|
|
|
|
private IEnumerator TeleportSameSceneCoroutine(OctoTeleporterData teleporter)
|
|
{
|
|
// Get global fade settings
|
|
OctoSettings.ScenesSettings.FadeTransitionSettings fadeSettings = OctoCore.Instance.Settings.Scenes.FadeSettings;
|
|
|
|
// Fade out
|
|
if (teleporter.UseFadeTransition && _fadeCanvas)
|
|
{
|
|
_fadeCanvas.FadeOut(fadeSettings.FadeOutDuration, fadeSettings.FadeColor);
|
|
yield return new WaitForSeconds(fadeSettings.FadeOutDuration);
|
|
}
|
|
|
|
// Find target teleporter
|
|
OctoTeleporter destination = OctoTeleporter.Find(teleporter);
|
|
|
|
if (destination)
|
|
{
|
|
MovePlayerToTeleporter(destination, teleporter.SetPlayerRotation);
|
|
destination.TriggerTeleport();
|
|
}
|
|
else
|
|
{
|
|
Debug.LogError("[OctoNavigation] Target teleporter not found: " + (teleporter ? teleporter.name : "null"));
|
|
}
|
|
|
|
// Fade in
|
|
if (teleporter.UseFadeTransition && _fadeCanvas)
|
|
{
|
|
_fadeCanvas.FadeIn(fadeSettings.FadeInDuration);
|
|
yield return new WaitForSeconds(fadeSettings.FadeInDuration);
|
|
}
|
|
|
|
OnTeleportCompleted?.Invoke(null, teleporter);
|
|
}
|
|
|
|
private IEnumerator TeleportDifferentSceneCoroutine(OctoTeleporterData teleporter)
|
|
{
|
|
// Get global fade settings
|
|
OctoSettings.ScenesSettings.FadeTransitionSettings fadeSettings = OctoCore.Instance.Settings.Scenes.FadeSettings;
|
|
|
|
// Fade out
|
|
if (teleporter.UseFadeTransition && _fadeCanvas)
|
|
{
|
|
_fadeCanvas.FadeOut(fadeSettings.FadeOutDuration, fadeSettings.FadeColor);
|
|
yield return new WaitForSeconds(fadeSettings.FadeOutDuration);
|
|
}
|
|
|
|
// Store pending teleporter
|
|
PendingTeleporter = teleporter;
|
|
_setPlayerRotation = teleporter.SetPlayerRotation;
|
|
|
|
if (OctoCore.Instance.Settings.Scenes.UseAddressables)
|
|
{
|
|
#if OCTO_ADDRESSABLES
|
|
AsyncOperationHandle<SceneInstance> handle = Addressables.LoadSceneAsync(teleporter.TargetScene.SceneName, LoadSceneMode.Single);
|
|
yield return handle;
|
|
|
|
if (handle.Status != AsyncOperationStatus.Succeeded)
|
|
{
|
|
Debug.LogError("[OctoNavigation] Failed to load scene: " + teleporter.TargetScene.SceneName);
|
|
PendingTeleporter = null;
|
|
yield break;
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
AsyncOperation asyncLoad = SceneManager.LoadSceneAsync(teleporter.TargetScene.SceneName);
|
|
yield return asyncLoad;
|
|
}
|
|
|
|
// CompletePendingTeleport will be handled by OctoTeleporters
|
|
}
|
|
|
|
public void EvaluatePendingTeleport(OctoTeleporter teleporter)
|
|
{
|
|
if (PendingTeleporter != null &&
|
|
teleporter != null &&
|
|
teleporter.TeleporterData != null &&
|
|
teleporter.TeleporterData == PendingTeleporter)
|
|
{
|
|
PendingTeleporter = null;
|
|
OctoCore.Instance.StartCoroutine(CompletePendingTeleport(teleporter));
|
|
}
|
|
}
|
|
|
|
private IEnumerator CompletePendingTeleport(OctoTeleporter teleporter)
|
|
{
|
|
if (teleporter)
|
|
{
|
|
MovePlayerToTeleporter(teleporter, _setPlayerRotation);
|
|
teleporter.TriggerTeleport();
|
|
}
|
|
else
|
|
{
|
|
Debug.LogError("[OctoNavigation] Target teleporter not found in new scene: " + teleporter.name);
|
|
}
|
|
|
|
// Get global fade settings
|
|
OctoSettings.ScenesSettings.FadeTransitionSettings fadeSettings = OctoCore.Instance.Settings.Scenes.FadeSettings;
|
|
|
|
// Fade in
|
|
if (_fadeCanvas)
|
|
{
|
|
_fadeCanvas.FadeIn(fadeSettings.FadeInDuration);
|
|
yield return new WaitForSeconds(fadeSettings.FadeInDuration);
|
|
}
|
|
|
|
OnTeleportCompleted?.Invoke(null, teleporter.TeleporterData);
|
|
}
|
|
|
|
private void MovePlayerToTeleporter(OctoTeleporter teleporter, bool setRotation)
|
|
{
|
|
if (Components.OctoPlayer.Instance)
|
|
{
|
|
Components.OctoPlayer.Instance.Teleport(teleporter.transform.position, setRotation ? teleporter.transform.rotation : Components.OctoPlayer.Instance.transform.rotation);
|
|
}
|
|
else if (OctoTeleporterProxy.Instance)
|
|
{
|
|
if (setRotation)
|
|
OctoTeleporterProxy.Instance.Teleport(teleporter.transform.position, teleporter.transform.rotation);
|
|
else
|
|
OctoTeleporterProxy.Instance.Teleport(teleporter.transform.position);
|
|
}
|
|
}
|
|
|
|
private void CreateFadeCanvas()
|
|
{
|
|
GameObject fadeObj = new GameObject("OctoSceneFade");
|
|
GameObject.DontDestroyOnLoad(fadeObj);
|
|
_fadeCanvas = fadeObj.AddComponent<OctoSceneFade>();
|
|
_fadeCanvas.Initialize();
|
|
}
|
|
}
|
|
} |