您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
215 行
7.2 KiB
215 行
7.2 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using UnityEngine;
|
|
using UnityEngine.SceneManagement;
|
|
|
|
|
|
public enum LevelState
|
|
{
|
|
Loading,
|
|
Loaded,
|
|
}
|
|
|
|
public struct LevelLayer
|
|
{
|
|
public AsyncOperation loadOperation;
|
|
}
|
|
|
|
public class Level
|
|
{
|
|
public LevelState state;
|
|
public string name;
|
|
public List<LevelLayer> layers = new List<LevelLayer>(10);
|
|
}
|
|
|
|
public class LevelManager
|
|
{
|
|
public static readonly string[] layerNames = new string[]
|
|
{
|
|
"background",
|
|
"gameplay",
|
|
};
|
|
|
|
public Level currentLevel { get; private set; }
|
|
|
|
public void Init()
|
|
{
|
|
}
|
|
|
|
public bool IsCurrentLevelLoaded()
|
|
{
|
|
return currentLevel != null && currentLevel.state == LevelState.Loaded;
|
|
}
|
|
|
|
public bool IsLoadingLevel()
|
|
{
|
|
return currentLevel != null && currentLevel.state == LevelState.Loading;
|
|
}
|
|
|
|
public bool CanLoadLevel(string name)
|
|
{
|
|
// TODO (petera). We can't really promise you can load a level before trying.
|
|
// Refactor to handle errors during load.
|
|
var bundle = SimpleBundleManager.LoadLevelAssetBundle(name);
|
|
return bundle != null;
|
|
}
|
|
|
|
public bool LoadLevel(string name)
|
|
{
|
|
if (currentLevel != null)
|
|
UnloadLevel();
|
|
|
|
// This is a pretty ugly hack to handle problems with loading camera and post processing volumes
|
|
// and those not being initalized at the same time. We simply disable the old camera and the
|
|
Game.game.TopCamera().enabled = false;
|
|
Game.game.BlackFade(true);
|
|
|
|
var newLevel = new Level();
|
|
newLevel.name = name;
|
|
|
|
// TODO (petera) Use async? Seem to be not needed here.
|
|
var bundle = SimpleBundleManager.LoadLevelAssetBundle(name);
|
|
if (bundle == null)
|
|
{
|
|
GameDebug.Log("Could not load asset bundle for scene " + name);
|
|
return false;
|
|
}
|
|
|
|
// Load using the name found in GetAllScenePaths because SceneManager.LoadSceneAsync is case sensitive
|
|
// yet name may not have correct casing as file system may be case insensitive
|
|
|
|
var scenePaths = new List<string>(bundle.GetAllScenePaths());
|
|
if (scenePaths.Count < 1)
|
|
{
|
|
GameDebug.Log("No scenes in asset bundle " + name);
|
|
return false;
|
|
}
|
|
|
|
// If there is a main scene, load that first
|
|
// TODO (petera) switch to LevelInfo based layers
|
|
var mainScenePath = scenePaths.Find(x => x.ToLower().EndsWith("_main.unity"));
|
|
var useLayers = true;
|
|
if (mainScenePath == null)
|
|
{
|
|
useLayers = false;
|
|
mainScenePath = scenePaths[0];
|
|
}
|
|
|
|
GameDebug.Log("Loading " + mainScenePath);
|
|
var mainLoadOperation = SceneManager.LoadSceneAsync(mainScenePath, LoadSceneMode.Single);
|
|
if (mainLoadOperation == null)
|
|
{
|
|
GameDebug.Log("Failed to load level : " + name);
|
|
return false;
|
|
}
|
|
|
|
currentLevel = newLevel;
|
|
currentLevel.layers.Add(new LevelLayer { loadOperation = mainLoadOperation });
|
|
|
|
if (!useLayers)
|
|
return true;
|
|
|
|
// Now load all additional layers that may be here
|
|
foreach (var l in layerNames)
|
|
{
|
|
var layerScenePath = scenePaths.Find(x => x.ToLower().EndsWith(l + ".unity"));
|
|
if (layerScenePath == null)
|
|
continue;
|
|
|
|
// TODO : Are we guaranteed that the scenes are initialized in order without setting allowactivation = false?
|
|
GameDebug.Log("+Loading " + layerScenePath);
|
|
var layerLoadOperation = SceneManager.LoadSceneAsync(layerScenePath, LoadSceneMode.Additive);
|
|
if (layerLoadOperation != null)
|
|
{
|
|
currentLevel.layers.Add(new LevelLayer { loadOperation = layerLoadOperation });
|
|
}
|
|
else
|
|
{
|
|
GameDebug.Log("Warning : Unable to load level layer : " + layerScenePath);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public void UnloadLevel()
|
|
{
|
|
if (currentLevel == null)
|
|
return;
|
|
|
|
if (currentLevel.state == LevelState.Loading)
|
|
throw new NotImplementedException("TODO : Implement unload during load");
|
|
|
|
// TODO (ulfj) : Load empty scene for now
|
|
SceneManager.LoadScene(1);
|
|
|
|
SimpleBundleManager.ReleaseLevelAssetBundle(currentLevel.name);
|
|
currentLevel = null;
|
|
}
|
|
|
|
public void Update()
|
|
{
|
|
if (currentLevel != null && currentLevel.state == LevelState.Loading)
|
|
{
|
|
var done = currentLevel.layers.All(l => l.loadOperation.isDone);
|
|
if (done)
|
|
{
|
|
// Do activation here?
|
|
currentLevel.state = LevelState.Loaded;
|
|
|
|
if (Game.GameLoopCount == 1)
|
|
{
|
|
if (Game.GetGameLoop<ServerGameLoop>() != null)
|
|
StripCode(BuildType.Server, true);
|
|
else if (Game.GetGameLoop<ClientGameLoop>() != null)
|
|
StripCode(BuildType.Client, true);
|
|
else
|
|
StripCode(BuildType.Default, true);
|
|
}
|
|
else
|
|
StripCode(BuildType.Default, true);
|
|
|
|
GameDebug.Log("Scene " + currentLevel.name + " loaded");
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// TODO (petera) this code was moved here to make it available outside of editor - until we start cooking for client/server
|
|
public enum BuildType
|
|
{
|
|
Default,
|
|
Client,
|
|
Server,
|
|
}
|
|
|
|
public static void StripCode(BuildType buildType, bool isDevelopmentBuild)
|
|
{
|
|
GameDebug.Log("Stripping code for " + buildType.ToString() + " (" + (isDevelopmentBuild ? "DevBuild" : "NonDevBuild") + ")");
|
|
var deleteBehaviors = new List<MonoBehaviour>();
|
|
var deleteGameObjects = new List<GameObject>();
|
|
|
|
foreach (var behavior in UnityEngine.Object.FindObjectsOfType<MonoBehaviour>())
|
|
{
|
|
if (behavior.GetType().GetCustomAttributes(typeof(EditorOnlyComponentAttribute), false).Length > 0)
|
|
deleteBehaviors.Add(behavior);
|
|
else if (behavior.GetType().GetCustomAttributes(typeof(EditorOnlyGameObjectAttribute), false).Length > 0)
|
|
deleteGameObjects.Add(behavior.gameObject);
|
|
else if (buildType == BuildType.Server && behavior.GetType().GetCustomAttributes(typeof(ClientOnlyComponentAttribute), false).Length > 0)
|
|
deleteBehaviors.Add(behavior);
|
|
else if (buildType == BuildType.Client && behavior.GetType().GetCustomAttributes(typeof(ServerOnlyComponentAttribute), false).Length > 0)
|
|
deleteBehaviors.Add(behavior);
|
|
else if (!isDevelopmentBuild && behavior.GetType().GetCustomAttributes(typeof(DevelopmentOnlyComponentAttribute), false).Length > 0)
|
|
deleteBehaviors.Add(behavior);
|
|
}
|
|
|
|
GameDebug.Log(string.Format("Stripping {0} game object(s) and {1} behavior(s)", deleteGameObjects.Count, deleteBehaviors.Count));
|
|
|
|
foreach (var gameObject in deleteGameObjects)
|
|
UnityEngine.Object.DestroyImmediate(gameObject);
|
|
|
|
foreach (var behavior in deleteBehaviors)
|
|
UnityEngine.Object.DestroyImmediate(behavior);
|
|
}
|
|
}
|