// Copyright (c) Pixel Crushers. All rights reserved.
using UnityEngine;
using System.Collections;
namespace PixelCrushers.DialogueSystem
{
///
/// This component combines Application.LoadLevel[Async] with the saved-game data
/// features of PersistentDataManager. To use it, add it to your Dialogue Manager
/// object and pass the saved-game data to LevelManager.LoadGame().
///
[AddComponentMenu("")] // Use wrapper.
public class LevelManager : MonoBehaviour
{
///
/// The default starting level to use if none is recorded in the saved-game data.
///
[Tooltip("Level to use if none is recorded in saved-game data.")]
public string defaultStartingLevel;
[Tooltip("Load asynchronously to prevent freeze while loading.")]
public bool useAsyncLoad = true;
///
/// Indicates whether a level is currently loading. Only useful in Unity Pro, which
/// uses Application.LoadLevelAsync().
///
/// true if loading; otherwise, false.
public bool isLoading { get; private set; }
/// @cond FOR_V1_COMPATIBILITY
public bool IsLoading { get { return isLoading; } set { isLoading = value; } }
/// @endcond
protected virtual void Awake()
{
isLoading = false;
}
protected virtual void OnEnable()
{
PersistentDataManager.RegisterPersistentData(gameObject);
}
protected virtual void OnDisable()
{
PersistentDataManager.UnregisterPersistentData(gameObject);
}
///
/// Loads the game recorded in the provided saveData.
///
/// Save data.
public void LoadGame(string saveData)
{
StartCoroutine(LoadLevelFromSaveData(saveData));
}
///
/// Restarts the game at the default starting level and resets the
/// Dialogue System to its initial database state.
///
public void RestartGame()
{
StartCoroutine(LoadLevelFromSaveData(null));
}
private IEnumerator LoadLevelFromSaveData(string saveData)
{
if (DialogueDebug.logInfo) Debug.Log("Dialogue System: LevelManager: Starting LoadLevelFromSaveData coroutine");
string levelName = defaultStartingLevel;
if (string.IsNullOrEmpty(saveData))
{
// If no saveData, reset the database.
if (DialogueDebug.logInfo) Debug.Log("Dialogue System: LevelManager: Save data is empty, so just resetting database");
DialogueManager.ResetDatabase(DatabaseResetOptions.RevertToDefault);
}
else
{
// Put saveData in Lua so we can get Variable["SavedLevelName"]:
if (DialogueDebug.logInfo) Debug.Log("Dialogue System: LevelManager: Applying save data to get value of 'SavedLevelName' variable");
Lua.Run(saveData, DialogueDebug.logInfo);
levelName = DialogueLua.GetVariable("SavedLevelName").asString;
if (string.IsNullOrEmpty(levelName) || string.Equals(levelName, "nil"))
{
levelName = defaultStartingLevel;
if (DialogueDebug.logInfo) Debug.Log("Dialogue System: LevelManager: 'SavedLevelName' isn't defined. Using default level " + levelName);
}
else
{
if (DialogueDebug.logInfo) Debug.Log("Dialogue System: LevelManager: SavedLevelName = " + levelName);
}
}
// Load the level:
PersistentDataManager.LevelWillBeUnloaded();
if (CanLoadAsync())
{
AsyncOperation async = Tools.LoadLevelAsync(levelName);
isLoading = true;
while (!async.isDone)
{
yield return null;
}
isLoading = false;
}
else
{
Tools.LoadLevel(levelName);
}
// Wait two frames for objects in the level to finish their Start() methods:
if (DialogueDebug.logInfo) Debug.Log("Dialogue System: LevelManager finished loading level " + levelName + ". Waiting 2 frames for scene objects to start.");
yield return null;
yield return null;
// Then apply saveData to the objects:
if (!string.IsNullOrEmpty(saveData))
{
if (DialogueDebug.logInfo) Debug.Log("Dialogue System: LevelManager waited 2 frames. Appling save data: " + saveData);
PersistentDataManager.ApplySaveData(saveData);
}
// Update quest tracker HUD:
DialogueManager.SendUpdateTracker();
}
///
/// Loads a level. Use to change levels while keeping data synced. This method
/// also calls PersistentDataManager.Record() before changing levels and
/// PersistentDataManager.Apply() after changing levels. After loading the level,
/// it waits two frames to allow GameObjects to finish their initialization first.
///
/// Level name.
public void LoadLevel(string levelName)
{
StartCoroutine(LoadLevelCoroutine(levelName, -1));
}
///
/// Loads a level. Use to change levels while keeping data synced. This method
/// also calls PersistentDataManager.Record() before changing levels and
/// PersistentDataManager.Apply() after changing levels. After loading the level,
/// it waits two frames to allow GameObjects to finish their initialization first.
///
/// Scene index in build settings.
public void LoadLevel(int levelIndex)
{
StartCoroutine(LoadLevelCoroutine(null, levelIndex));
}
private IEnumerator LoadLevelCoroutine(string levelName, int levelIndex)
{
PersistentDataManager.Record();
// Load the level:
PersistentDataManager.LevelWillBeUnloaded();
if (CanLoadAsync())
{
AsyncOperation async = !string.IsNullOrEmpty(levelName) ? Tools.LoadLevelAsync(levelName) : Tools.LoadLevelAsync(levelIndex);
isLoading = true;
while (!async.isDone)
{
yield return null;
}
isLoading = false;
}
else
{
if (!string.IsNullOrEmpty(levelName)) Tools.LoadLevel(levelName); else Tools.LoadLevel(levelIndex);
}
// Wait two frames for objects in the level to finish their Start() methods:
yield return null;
yield return null;
// Apply position data, but don't apply player's position:
var player = GameObject.FindGameObjectWithTag("Player");
var persistentPos = (player != null) ? player.GetComponent() : null;
var originalValue = false;
if (persistentPos != null)
{
originalValue = persistentPos.restoreCurrentLevelPosition;
persistentPos.restoreCurrentLevelPosition = false;
}
PersistentDataManager.Apply();
if (persistentPos != null)
{
persistentPos.restoreCurrentLevelPosition = originalValue;
}
// Update quest tracker HUD:
DialogueManager.SendUpdateTracker();
}
private bool CanLoadAsync()
{
return useAsyncLoad;
}
///
/// Records the current level in Lua.
///
public virtual void OnRecordPersistentData()
{
DialogueLua.SetVariable("SavedLevelName", Tools.loadedLevelName);
}
}
}