219 lines
6.5 KiB
C#
219 lines
6.5 KiB
C#
using System.Collections;
|
|
using OctoCore.Navigation.Data;
|
|
using OctoCore.Preloading;
|
|
using OctoCore.UI;
|
|
using UnityEngine;
|
|
using UnityEngine.EventSystems;
|
|
using UnityEngine.UI;
|
|
|
|
namespace OctoCore.Navigation
|
|
{
|
|
/// <summary>
|
|
/// Main menu manager.
|
|
/// Handles Play, Quit and optional extra buttons.
|
|
/// Relies on OctoCore.Navigation for scene loading.
|
|
/// </summary>
|
|
public class OctoMainMenu : MonoBehaviour
|
|
{
|
|
[Header("Scene Settings")]
|
|
[SerializeField, Tooltip("First scene to load on Play")]
|
|
private OctoSceneData _firstSceneData;
|
|
|
|
[Header("Preloading")]
|
|
[SerializeField, Tooltip("Optional. If null, the menu will search or create one at runtime.")]
|
|
private OctoSmartPreloader _preloader;
|
|
|
|
[SerializeField, Tooltip("Preload every scene manifest before loading the first scene.")]
|
|
private bool _preloadAllBeforePlay = true;
|
|
|
|
[Header("UI Settings")]
|
|
[SerializeField, Tooltip("Optional panel to show/hide (options, credits...)")]
|
|
private GameObject _optionalPanel;
|
|
|
|
[SerializeField] private GameObject _loadingScreen;
|
|
[SerializeField] private GameObject _loadingWheel;
|
|
|
|
[SerializeField] private Button _optionalPanelFirstButton;
|
|
[SerializeField] private Button _mainPanelDefaultButton;
|
|
|
|
private bool _isLoading = false;
|
|
|
|
private void Awake()
|
|
{
|
|
if (_optionalPanel)
|
|
_optionalPanel.SetActive(false);
|
|
|
|
if (_loadingScreen)
|
|
_loadingScreen.SetActive(false);
|
|
|
|
Cursor.visible = true;
|
|
Cursor.lockState = CursorLockMode.None;
|
|
|
|
ResolvePreloader();
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
if (_isLoading && _loadingWheel)
|
|
_loadingWheel.transform.Rotate(0, 0, -200f * Time.deltaTime);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Load the first scene. Called by the Play button.
|
|
/// </summary>
|
|
public void OnPlayButton()
|
|
{
|
|
if (_isLoading)
|
|
return;
|
|
|
|
if (!OctoCore.Instance)
|
|
{
|
|
Debug.LogError("[OctoMainMenu] OctoCore instance not found");
|
|
return;
|
|
}
|
|
|
|
if (_firstSceneData == null)
|
|
{
|
|
Debug.LogError("[OctoMainMenu] FirstSceneData is null");
|
|
return;
|
|
}
|
|
|
|
StartCoroutine(PlayRoutine());
|
|
}
|
|
|
|
private IEnumerator PlayRoutine()
|
|
{
|
|
_isLoading = true;
|
|
|
|
if (_loadingScreen)
|
|
_loadingScreen.SetActive(true);
|
|
|
|
yield return null;
|
|
yield return null;
|
|
|
|
float minimumVisibleLoadingTime = 2f;
|
|
float timer = 0f;
|
|
|
|
while (timer < minimumVisibleLoadingTime)
|
|
{
|
|
timer += Time.deltaTime;
|
|
yield return null;
|
|
}
|
|
|
|
if (_preloadAllBeforePlay)
|
|
{
|
|
ResolvePreloader();
|
|
|
|
if (_preloader == null)
|
|
{
|
|
Debug.LogError("[OctoMainMenu] OctoSmartPreloader not found and could not be created.");
|
|
_isLoading = false;
|
|
yield break;
|
|
}
|
|
|
|
yield return _preloader.PreloadAllScenesRoutine();
|
|
|
|
if (!_preloader.IsReady)
|
|
{
|
|
Debug.LogWarning("[OctoMainMenu] Preloader finished but IsReady is false. Continuing anyway.");
|
|
}
|
|
}
|
|
|
|
_isLoading = false;
|
|
|
|
OctoCore.Instance.Navigation.LoadScene(_firstSceneData);
|
|
}
|
|
|
|
private void ResolvePreloader()
|
|
{
|
|
if (_preloader != null)
|
|
return;
|
|
|
|
#if UNITY_2023_1_OR_NEWER
|
|
_preloader = Object.FindFirstObjectByType<OctoSmartPreloader>();
|
|
#else
|
|
_preloader = Object.FindObjectOfType<OctoSmartPreloader>();
|
|
#endif
|
|
|
|
if (_preloader != null)
|
|
return;
|
|
|
|
GameObject preloaderObject = new GameObject("OctoSmartPreloader");
|
|
_preloader = preloaderObject.AddComponent<OctoSmartPreloader>();
|
|
|
|
_preloader.AutoLoadDatabaseFromResources = true;
|
|
_preloader.DatabaseResourcesPath = "OctoPreload/OctoPreloadDatabase";
|
|
_preloader.DontDestroyOnLoadObject = true;
|
|
|
|
// We want to start preloading only when the player presses Play.
|
|
_preloader.PreloadAllOnStart = false;
|
|
|
|
// Full boot preload mode.
|
|
_preloader.KeepAllLoadedForEntireGame = true;
|
|
|
|
// Safe defaults.
|
|
_preloader.ItemsPerFrame = 32;
|
|
_preloader.WarmupShaderVariants = true;
|
|
_preloader.WarmupAllShadersAtEnd = false;
|
|
_preloader.TouchMaterials = true;
|
|
_preloader.TouchTextures = true;
|
|
_preloader.TouchMeshes = true;
|
|
_preloader.TouchAudioClips = false;
|
|
_preloader.WarmupParticlePrefabs = true;
|
|
_preloader.LogProgress = true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Quit the application. Called by the Quit button.
|
|
/// </summary>
|
|
public void OnQuitButton()
|
|
{
|
|
Application.Quit();
|
|
|
|
#if UNITY_EDITOR
|
|
UnityEditor.EditorApplication.isPlaying = false;
|
|
#endif
|
|
}
|
|
|
|
/// <summary>
|
|
/// Toggle an optional panel (options, credits...). Called by any extra button.
|
|
/// </summary>
|
|
public void OnTogglePanel()
|
|
{
|
|
if (_optionalPanel)
|
|
{
|
|
bool newState = !_optionalPanel.activeSelf;
|
|
_optionalPanel.SetActive(newState);
|
|
}
|
|
}
|
|
|
|
public void SelectMainDefaultButton()
|
|
{
|
|
StartCoroutine(SelectAfterFrame(_mainPanelDefaultButton));
|
|
}
|
|
|
|
public void SelectDebugFirstButton()
|
|
{
|
|
StartCoroutine(SelectAfterFrame(_optionalPanelFirstButton));
|
|
}
|
|
|
|
private IEnumerator SelectAfterFrame(Button button)
|
|
{
|
|
MultiTargetButton.ClearPersistence();
|
|
|
|
if (button != null && EventSystem.current != null)
|
|
EventSystem.current.SetSelectedGameObject(button.gameObject);
|
|
|
|
OctoMainMenu.IgnoreMouseUntil = Time.time + 0.1f;
|
|
yield break;
|
|
}
|
|
|
|
// Exposed so MultiTargetButton can check before activating on hover.
|
|
public static float IgnoreMouseUntil = 0f;
|
|
|
|
public void ClearButtonPersistence()
|
|
{
|
|
MultiTargetButton.ClearPersistence();
|
|
}
|
|
}
|
|
} |