356 lines
9.1 KiB
C#
356 lines
9.1 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using UnityEngine.UI;
|
|
|
|
namespace BlockSpace.Worlds
|
|
{
|
|
[DisallowMultipleComponent]
|
|
public sealed class WorldLoadingScreenController : MonoBehaviour
|
|
{
|
|
private struct CameraState
|
|
{
|
|
public CameraClearFlags clearFlags;
|
|
|
|
public Color backgroundColor;
|
|
}
|
|
|
|
private struct RigidbodyState
|
|
{
|
|
public Vector3 linearVelocity;
|
|
|
|
public Vector3 angularVelocity;
|
|
}
|
|
|
|
[SerializeField]
|
|
private GameObject loadingScreenObject;
|
|
|
|
[SerializeField]
|
|
private Slider progressSlider;
|
|
|
|
[SerializeField]
|
|
private bool hideSceneWhileLoading = true;
|
|
|
|
[SerializeField]
|
|
private int requiredTeleportsToComplete = 2;
|
|
|
|
private readonly Dictionary<Renderer, bool> rendererStates = new Dictionary<Renderer, bool>();
|
|
|
|
private readonly Dictionary<Canvas, bool> canvasStates = new Dictionary<Canvas, bool>();
|
|
|
|
private readonly Dictionary<Graphic, bool> graphicStates = new Dictionary<Graphic, bool>();
|
|
|
|
private readonly Dictionary<Camera, CameraState> cameraStates = new Dictionary<Camera, CameraState>();
|
|
|
|
private readonly Dictionary<Behaviour, bool> movementBehaviourStates = new Dictionary<Behaviour, bool>();
|
|
|
|
private readonly Dictionary<Rigidbody, RigidbodyState> rigidbodyStates = new Dictionary<Rigidbody, RigidbodyState>();
|
|
|
|
private bool loading;
|
|
|
|
private int completedTeleports;
|
|
|
|
public static WorldLoadingScreenController Instance { get; private set; }
|
|
|
|
public bool IsLoading => loading;
|
|
|
|
public static event Action LoadingFinished;
|
|
|
|
public void Configure(GameObject screenObject, Slider slider)
|
|
{
|
|
if (screenObject != null)
|
|
{
|
|
loadingScreenObject = screenObject;
|
|
}
|
|
if (slider != null)
|
|
{
|
|
progressSlider = slider;
|
|
}
|
|
if (!loading)
|
|
{
|
|
SetScreenVisible(visible: false);
|
|
}
|
|
}
|
|
|
|
private void Awake()
|
|
{
|
|
if (Instance != null && Instance != this)
|
|
{
|
|
Debug.LogWarning("Multiple WorldLoadingScreenController instances found. Using the latest active instance.", this);
|
|
}
|
|
Instance = this;
|
|
SetScreenVisible(visible: false);
|
|
SetProgress(0f);
|
|
}
|
|
|
|
private void OnDisable()
|
|
{
|
|
SetLoading(isLoading: false);
|
|
}
|
|
|
|
private void OnDestroy()
|
|
{
|
|
if (Instance == this)
|
|
{
|
|
Instance = null;
|
|
}
|
|
}
|
|
|
|
public void BeginLoading(float initialProgress = 0f)
|
|
{
|
|
completedTeleports = 0;
|
|
SetLoading(isLoading: true);
|
|
SetProgress(initialProgress);
|
|
}
|
|
|
|
public void SetLoading(bool isLoading)
|
|
{
|
|
if (loading == isLoading)
|
|
{
|
|
SetScreenVisible(isLoading);
|
|
return;
|
|
}
|
|
loading = isLoading;
|
|
SetScreenVisible(isLoading);
|
|
if (hideSceneWhileLoading)
|
|
{
|
|
if (isLoading)
|
|
{
|
|
HideScene();
|
|
}
|
|
else
|
|
{
|
|
RestoreScene();
|
|
}
|
|
}
|
|
if (isLoading)
|
|
{
|
|
DisableMovement();
|
|
}
|
|
else
|
|
{
|
|
RestoreMovement();
|
|
}
|
|
if (!isLoading)
|
|
{
|
|
completedTeleports = 0;
|
|
SetProgress(0f);
|
|
WorldLoadingScreenController.LoadingFinished?.Invoke();
|
|
}
|
|
}
|
|
|
|
public void SetCheckpoint(float progress)
|
|
{
|
|
if (loading && (!(progressSlider != null) || !(progress < progressSlider.value)))
|
|
{
|
|
SetProgress(progress);
|
|
}
|
|
}
|
|
|
|
public void NotifyLocalPlayerTeleported(bool forceComplete = false)
|
|
{
|
|
if (loading)
|
|
{
|
|
completedTeleports++;
|
|
if (!forceComplete && completedTeleports < Mathf.Max(1, requiredTeleportsToComplete))
|
|
{
|
|
SetCheckpoint(0.97f);
|
|
}
|
|
else
|
|
{
|
|
CompleteLoading();
|
|
}
|
|
}
|
|
}
|
|
|
|
public void CompleteLoading()
|
|
{
|
|
if (loading)
|
|
{
|
|
SetProgress(1f);
|
|
SetLoading(isLoading: false);
|
|
}
|
|
}
|
|
|
|
public void SetProgress(float progress)
|
|
{
|
|
if (loading && hideSceneWhileLoading)
|
|
{
|
|
HideScene();
|
|
}
|
|
if (!(progressSlider == null))
|
|
{
|
|
progressSlider.minValue = 0f;
|
|
progressSlider.maxValue = 1f;
|
|
progressSlider.value = Mathf.Clamp01(progress);
|
|
}
|
|
}
|
|
|
|
private void SetScreenVisible(bool visible)
|
|
{
|
|
if (loadingScreenObject != null)
|
|
{
|
|
loadingScreenObject.SetActive(visible);
|
|
}
|
|
}
|
|
|
|
private void HideScene()
|
|
{
|
|
Transform loadingRoot = ((loadingScreenObject != null) ? loadingScreenObject.transform : base.transform);
|
|
Renderer[] array = UnityEngine.Object.FindObjectsByType<Renderer>(FindObjectsInactive.Include, FindObjectsSortMode.None);
|
|
foreach (Renderer renderer in array)
|
|
{
|
|
if (!(renderer == null) && !rendererStates.ContainsKey(renderer) && !IsInsideLoadingScreen(renderer.transform, loadingRoot))
|
|
{
|
|
rendererStates[renderer] = renderer.enabled;
|
|
renderer.enabled = false;
|
|
}
|
|
}
|
|
Canvas[] array2 = UnityEngine.Object.FindObjectsByType<Canvas>(FindObjectsInactive.Include, FindObjectsSortMode.None);
|
|
foreach (Canvas canvas in array2)
|
|
{
|
|
if (!(canvas == null) && !canvasStates.ContainsKey(canvas) && !IsInsideLoadingScreen(canvas.transform, loadingRoot))
|
|
{
|
|
canvasStates[canvas] = canvas.enabled;
|
|
canvas.enabled = false;
|
|
}
|
|
}
|
|
Graphic[] array3 = UnityEngine.Object.FindObjectsByType<Graphic>(FindObjectsInactive.Include, FindObjectsSortMode.None);
|
|
foreach (Graphic graphic in array3)
|
|
{
|
|
if (!(graphic == null) && !graphicStates.ContainsKey(graphic) && !IsInsideLoadingScreen(graphic.transform, loadingRoot))
|
|
{
|
|
graphicStates[graphic] = graphic.enabled;
|
|
graphic.enabled = false;
|
|
}
|
|
}
|
|
Camera[] array4 = UnityEngine.Object.FindObjectsByType<Camera>(FindObjectsInactive.Include, FindObjectsSortMode.None);
|
|
foreach (Camera camera in array4)
|
|
{
|
|
if (!(camera == null) && !cameraStates.ContainsKey(camera))
|
|
{
|
|
cameraStates[camera] = new CameraState
|
|
{
|
|
clearFlags = camera.clearFlags,
|
|
backgroundColor = camera.backgroundColor
|
|
};
|
|
camera.clearFlags = CameraClearFlags.Color;
|
|
camera.backgroundColor = Color.black;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void RestoreScene()
|
|
{
|
|
foreach (KeyValuePair<Renderer, bool> rendererState in rendererStates)
|
|
{
|
|
if (rendererState.Key != null)
|
|
{
|
|
rendererState.Key.enabled = rendererState.Value;
|
|
}
|
|
}
|
|
foreach (KeyValuePair<Canvas, bool> canvasState in canvasStates)
|
|
{
|
|
if (canvasState.Key != null)
|
|
{
|
|
canvasState.Key.enabled = canvasState.Value;
|
|
}
|
|
}
|
|
foreach (KeyValuePair<Graphic, bool> graphicState in graphicStates)
|
|
{
|
|
if (graphicState.Key != null)
|
|
{
|
|
graphicState.Key.enabled = graphicState.Value;
|
|
}
|
|
}
|
|
foreach (KeyValuePair<Camera, CameraState> cameraState in cameraStates)
|
|
{
|
|
if (cameraState.Key != null)
|
|
{
|
|
cameraState.Key.clearFlags = cameraState.Value.clearFlags;
|
|
cameraState.Key.backgroundColor = cameraState.Value.backgroundColor;
|
|
}
|
|
}
|
|
rendererStates.Clear();
|
|
canvasStates.Clear();
|
|
graphicStates.Clear();
|
|
cameraStates.Clear();
|
|
}
|
|
|
|
private void DisableMovement()
|
|
{
|
|
Behaviour[] array = UnityEngine.Object.FindObjectsByType<Behaviour>(FindObjectsInactive.Include, FindObjectsSortMode.None);
|
|
foreach (Behaviour behaviour in array)
|
|
{
|
|
if (!(behaviour == null) && !movementBehaviourStates.ContainsKey(behaviour) && IsMovementBehaviour(behaviour))
|
|
{
|
|
movementBehaviourStates[behaviour] = behaviour.enabled;
|
|
behaviour.enabled = false;
|
|
}
|
|
}
|
|
Rigidbody[] array2 = UnityEngine.Object.FindObjectsByType<Rigidbody>(FindObjectsInactive.Include, FindObjectsSortMode.None);
|
|
foreach (Rigidbody rigidbody in array2)
|
|
{
|
|
if (!(rigidbody == null) && !rigidbodyStates.ContainsKey(rigidbody))
|
|
{
|
|
rigidbodyStates[rigidbody] = new RigidbodyState
|
|
{
|
|
linearVelocity = rigidbody.linearVelocity,
|
|
angularVelocity = rigidbody.angularVelocity
|
|
};
|
|
rigidbody.linearVelocity = Vector3.zero;
|
|
rigidbody.angularVelocity = Vector3.zero;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void RestoreMovement()
|
|
{
|
|
foreach (KeyValuePair<Behaviour, bool> movementBehaviourState in movementBehaviourStates)
|
|
{
|
|
if (movementBehaviourState.Key != null)
|
|
{
|
|
movementBehaviourState.Key.enabled = movementBehaviourState.Value;
|
|
}
|
|
}
|
|
foreach (KeyValuePair<Rigidbody, RigidbodyState> rigidbodyState in rigidbodyStates)
|
|
{
|
|
if (rigidbodyState.Key != null)
|
|
{
|
|
rigidbodyState.Key.linearVelocity = rigidbodyState.Value.linearVelocity;
|
|
rigidbodyState.Key.angularVelocity = rigidbodyState.Value.angularVelocity;
|
|
}
|
|
}
|
|
movementBehaviourStates.Clear();
|
|
rigidbodyStates.Clear();
|
|
}
|
|
|
|
private bool IsMovementBehaviour(Behaviour behaviour)
|
|
{
|
|
if (behaviour == this)
|
|
{
|
|
return false;
|
|
}
|
|
string text = behaviour.GetType().Name;
|
|
if (!((behaviour.GetType().FullName ?? string.Empty) == "GorillaLocomotion.Player") && !(text == "DesktopRigController") && !(text == "CreatorFlightController") && !text.Contains("LocomotionProvider") && !text.Contains("MoveProvider") && !text.Contains("TurnProvider") && !text.Contains("JumpProvider") && !text.Contains("TeleportationProvider") && !text.Contains("ClimbProvider") && !text.Contains("ContinuousMove") && !text.Contains("DynamicMove") && !text.Contains("SnapTurn"))
|
|
{
|
|
return text.Contains("SmoothTurn");
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private bool IsInsideLoadingScreen(Transform target, Transform loadingRoot)
|
|
{
|
|
if (target != null && loadingRoot != null)
|
|
{
|
|
if (!(target == loadingRoot) && !target.IsChildOf(loadingRoot))
|
|
{
|
|
return loadingRoot.IsChildOf(target);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
}
|