OctoCore 0.0.1

This commit is contained in:
Alexandre Coirier
2026-02-09 23:53:14 +01:00
parent 85bf743cba
commit 80d0faf8a7
235 changed files with 13656 additions and 32 deletions
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 5d2ab646438037043aad58a513ed2e03
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,38 @@
using UnityEngine;
namespace OctoCore.Navigation.Data
{
/// <summary>
/// Scene configuration data.
/// Contains all settings for a specific scene.
/// </summary>
[CreateAssetMenu(fileName = "scene_", menuName = "Octo/Scenes/Scene Data", order = 0)]
public class OctoSceneData : ScriptableObject
{
/// <summary>
/// Unique identifier for this scene.
/// Automatically set to the asset name.
/// </summary>
[OctoReadOnly] public string Id;
/// <summary>
/// Scene name in Build Settings or Addressables.
/// </summary>
[Tooltip("Scene name in Build Settings or Addressables")]
public string SceneName;
/// <summary>
/// Enable fade transition when loading this scene.
/// </summary>
[Tooltip("Enable fade transition")]
public bool UseFadeTransition = true;
#if UNITY_EDITOR
void OnValidate()
{
Id = name;
UnityEditor.EditorUtility.SetDirty(this);
}
#endif
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: a1f04313388f6a846a9e2a6bfe6e985a
@@ -0,0 +1,44 @@
using UnityEngine;
namespace OctoCore.Navigation.Data
{
/// <summary>
/// Teleporter configuration data.
/// Defines teleportation behavior between locations or scenes.
/// </summary>
[CreateAssetMenu(fileName = "teleporter_", menuName = "Octo/Scenes/Teleporter Data", order = 1)]
public class OctoTeleporterData : ScriptableObject
{
/// <summary>
/// Unique identifier for this teleporter.
/// Automatically set to the asset name.
/// </summary>
[OctoReadOnly] public string Id;
/// <summary>
/// Target scene to load (null = stay in current scene).
/// </summary>
[Tooltip("Target scene (null = same scene)")]
public OctoSceneData TargetScene;
/// <summary>
/// Set player rotation to match destination teleporter orientation.
/// </summary>
[Tooltip("Player orientation after teleport")]
public bool SetPlayerRotation = true;
/// <summary>
/// Enable fade transition during teleport.
/// </summary>
[Tooltip("Enable fade transition")]
public bool UseFadeTransition = true;
#if UNITY_EDITOR
void OnValidate()
{
Id = name;
UnityEditor.EditorUtility.SetDirty(this);
}
#endif
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 01c67a8f36397f441b79c801b74560f1
@@ -0,0 +1,333 @@
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();
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 52668fd3a36f7d54a9180e2dd4946e37
@@ -0,0 +1,118 @@
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
namespace OctoCore.Navigation
{
/// <summary>
/// Handles fade in/out transitions for scene loading and teleportation.
/// </summary>
public class OctoSceneFade : MonoBehaviour
{
private Canvas _canvas;
private Image _fadeImage;
private IEnumerator fadeOutCoroutine;
private IEnumerator fadeInCoroutine;
/// <summary>
/// Initialize the fade canvas and image.
/// </summary>
public void Initialize()
{
// Create canvas
_canvas = gameObject.AddComponent<Canvas>();
_canvas.renderMode = RenderMode.ScreenSpaceOverlay;
_canvas.sortingOrder = 9999;
gameObject.AddComponent<CanvasScaler>();
gameObject.AddComponent<GraphicRaycaster>();
// Create fade image
GameObject imageObj = new GameObject("FadeImage");
imageObj.transform.SetParent(transform);
_fadeImage = imageObj.AddComponent<Image>();
_fadeImage.color = new Color(0, 0, 0, 0);
RectTransform rt = _fadeImage.GetComponent<RectTransform>();
rt.anchorMin = Vector2.zero;
rt.anchorMax = Vector2.one;
rt.sizeDelta = rt.anchoredPosition = Vector2.zero;
_canvas.enabled = false;
}
/// <summary>
/// Fade out to specified color over duration.
/// </summary>
public void FadeOut(float duration, Color color)
{
if (fadeOutCoroutine == null)
{
if (fadeInCoroutine != null)
StopCoroutine(fadeInCoroutine);
StartCoroutine(fadeOutCoroutine = FadeOutCoroutine(duration, color));
}
}
/// <summary>
/// Fade in from current color to transparent over duration.
/// </summary>
public void FadeIn(float duration)
{
if (fadeInCoroutine == null)
{
if (fadeOutCoroutine != null)
StopCoroutine(fadeOutCoroutine);
StartCoroutine(fadeInCoroutine = FadeInCoroutine(duration));
}
}
private IEnumerator FadeOutCoroutine(float duration, Color color)
{
_canvas.enabled = true;
Color startColor = new Color(color.r, color.g, color.b, 0);
Color endColor = new Color(color.r, color.g, color.b, 1);
for (float t = 0; t < duration; t += Time.unscaledDeltaTime)
{
float normalizedTime = Mathf.Clamp01(t / duration);
_fadeImage.color = Color.Lerp(startColor, endColor, normalizedTime);
yield return new WaitForEndOfFrame();
}
_fadeImage.color = endColor;
fadeOutCoroutine = null;
}
/// <summary>
/// Fade in from current color to transparent over duration.
/// </summary>
private IEnumerator FadeInCoroutine(float duration)
{
Color startColor = _fadeImage.color;
if (startColor != Color.clear)
{
Color endColor = new Color(startColor.r, startColor.g, startColor.b, 0);
for (float t = 0; t < duration; t += Time.unscaledDeltaTime)
{
float normalizedTime = Mathf.Clamp01(t / duration);
_fadeImage.color = Color.Lerp(startColor, endColor, normalizedTime);
yield return new WaitForEndOfFrame();
}
_fadeImage.color = endColor;
_canvas.enabled = false;
}
fadeInCoroutine = null;
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 53bf408fb989ba342a38b073dd1dafd1
@@ -0,0 +1,37 @@
using UnityEngine;
using OctoCore.Navigation.Data;
namespace OctoCore.Navigation
{
/// <summary>
/// Scene trigger component.
/// Links OctoWorldEvent to the scene loading system.
/// Call LoadScene() from OctoWorldEvent to load a scene.
/// </summary>
public class OctoSceneTrigger : MonoBehaviour
{
[SerializeField, Tooltip("Scene data to load")]
private OctoSceneData _sceneData;
/// <summary>
/// Load the configured scene.
/// This method should be called from OctoWorldEvent.
/// </summary>
public void LoadScene()
{
if (!OctoCore.Instance)
{
Debug.LogError("[OctoSceneTrigger] OctoCore instance not found");
return;
}
if (_sceneData == null)
{
Debug.LogError("[OctoSceneTrigger] SceneData is null");
return;
}
OctoCore.Instance.Navigation.LoadScene(_sceneData);
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 67296e1c23d8b3645add1d503a4b3a3f
@@ -0,0 +1,70 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using OctoCore.Navigation.Data;
namespace OctoCore.Navigation
{
/// <summary>
/// Teleporter destination component.
/// Marks a position as a valid teleport arrival point.
/// </summary>
public class OctoTeleporter : MonoBehaviour
{
private static List<OctoTeleporter> Teleporters = new List<OctoTeleporter>();
[SerializeField, Tooltip("Teleporter data identifying this destination")]
private OctoTeleporterData _teleporterData;
[SerializeField, Tooltip("Event triggered when player teleports to this location")]
private UnityEvent _onTeleport;
/// <summary>
/// Teleporter data for this destination.
/// </summary>
public OctoTeleporterData TeleporterData => _teleporterData;
/// <summary>
/// Find a teleporter by its data reference.
/// </summary>
public static OctoTeleporter Find(OctoTeleporterData data)
{
if (data == null)
return null;
foreach (var teleporter in Teleporters)
{
if (teleporter._teleporterData == data)
return teleporter;
}
return null;
}
void OnEnable()
{
if (!Teleporters.Contains(this))
Teleporters.Add(this);
if (OctoCore.Instance)
OctoCore.Instance.Navigation.EvaluatePendingTeleport(this);
}
void OnDisable()
{
Teleporters.Remove(this);
}
/// <summary>
/// Trigger the teleport event.
/// Called by OctoNavigation when player arrives.
/// </summary>
public void TriggerTeleport()
{
_onTeleport?.Invoke();
if (OctoCore.Instance && OctoCore.Instance.Development.Log)
Debug.Log("[OctoTeleporter] Teleported to: " + (_teleporterData ? _teleporterData.name : "Unknown"));
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 7b476baeb59f80b42aaa56a0901de859
@@ -0,0 +1,42 @@
using UnityEngine;
using UnityEngine.Events;
namespace OctoCore.Navigation
{
public class OctoTeleporterProxy : MonoBehaviour
{
public static OctoTeleporterProxy Instance { get; private set; }
[SerializeField] private UnityEvent<bool> _onPreTeleport;
[SerializeField] private UnityEvent<Vector3> _setPositon;
[SerializeField] private UnityEvent<Quaternion> _setRotation;
[SerializeField] private UnityEvent<bool> _onPostTeleport;
void OnEnable()
{
if (Instance != null)
{
Debug.LogWarning("Only one OctoTeleporterProxy per scene is supported");
return;
}
Instance = this;
}
void OnDisable()
{
if (Instance == this)
Instance = null;
}
public void Teleport(Vector3 position) { Teleport(position, Quaternion.identity, false); }
public void Teleport(Vector3 position, Quaternion rotation, bool setRotation = true)
{
_onPreTeleport?.Invoke(false);
_setPositon?.Invoke(position);
if (setRotation)
_setRotation?.Invoke(rotation);
_onPostTeleport?.Invoke(true);
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 2f788fcf1ffcc3342b6e7a87661a4262
@@ -0,0 +1,37 @@
using UnityEngine;
using OctoCore.Navigation.Data;
namespace OctoCore.Navigation
{
/// <summary>
/// Teleporter trigger component.
/// Links OctoWorldEvent to the teleportation system.
/// Call Teleport() from OctoWorldEvent to initiate teleportation.
/// </summary>
public class OctoTeleporterTrigger : MonoBehaviour
{
[SerializeField, Tooltip("Teleporter to teleport to")]
private OctoTeleporterData _teleporter;
/// <summary>
/// Initiate teleportation to the configured teleporter.
/// This method should be called from OctoWorldEvent.
/// </summary>
public void Teleport()
{
if (!OctoCore.Instance)
{
Debug.LogError("[OctoTeleporterTrigger] OctoCore instance not found");
return;
}
if (_teleporter == null)
{
Debug.LogError("[OctoTeleporterTrigger] Teleporter is null");
return;
}
OctoCore.Instance.Navigation.Teleport(_teleporter);
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 981114d2a43791f40bc46a5ae85cc02d