This wrapper essentially restricts the logger to the unity console, when using WebGL, while I don't need to change any Reference to LogManager or Log.Debug(etc) in my code.
435 lines
13 KiB
C#
435 lines
13 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.IO;
|
|
using System.Reflection;
|
|
using UnityEngine;
|
|
using UnityEngine.Events;
|
|
using UnityEngine.SceneManagement;
|
|
using FishNet;
|
|
using System.Collections.Generic;
|
|
using UnityEditor;
|
|
using log4net.Config;
|
|
using log4net;
|
|
/// <summary>
|
|
/// The available scenes in the order they are in the build settings.
|
|
/// </summary>
|
|
public enum Scenes
|
|
{
|
|
GameMangement,
|
|
MainMenu,
|
|
InGameUI,
|
|
Arena,
|
|
}
|
|
|
|
namespace Managers
|
|
{
|
|
|
|
/// <summary>
|
|
/// Starts up the game and it's managers.
|
|
/// Provides methods for loading additional scenes and triggering custom events when loaded.
|
|
/// Orchestrates the managers for starting local and online matches.
|
|
public class GameManager : MonoBehaviour
|
|
{
|
|
|
|
private static readonly ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
|
|
|
/// <summary>
|
|
/// Globally accessible member to use manager with.
|
|
/// </summary>
|
|
public static GameManager G { get; private set; }
|
|
|
|
[SerializeField]
|
|
private UIManager UIManager;
|
|
[SerializeField]
|
|
private CharacterManager CharacterManager;
|
|
[SerializeField]
|
|
private ControlsManager ControlsManager;
|
|
[SerializeField]
|
|
private MatchManager MatchManager;
|
|
[SerializeField]
|
|
private StatisticsManager StatisticsManager;
|
|
[SerializeField]
|
|
private PlayerManager PlayerManager;
|
|
[SerializeField]
|
|
private AudioManager AudioManager;
|
|
|
|
[SerializeField]
|
|
private GameObject startCamera;
|
|
|
|
public bool IsTestRun = false;
|
|
public Scenes TestScene = Scenes.Arena;
|
|
|
|
public event EventHandler<SceneLoadEventArgs> CustomSceneLoaded;
|
|
|
|
void Awake()
|
|
{
|
|
G = this;
|
|
if (!IsTestRun) ShowStartScreen();
|
|
LogManager.ConfigureLogging();
|
|
Log.Info("Awake");
|
|
}
|
|
|
|
void Start()
|
|
{
|
|
InstantiateBaseManagers();
|
|
Log.Info("Space Smash Out is starting.");
|
|
if (!IsTestRun)
|
|
{
|
|
LoadMainMenu();
|
|
}
|
|
else
|
|
{
|
|
// Coroutine for waiting a frame and letting the managers run their Start methods
|
|
StartCoroutine(SetupTestMatch(TestScene));
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Instantiates the managers needed to play the game.
|
|
/// </summary>
|
|
void InstantiateBaseManagers()
|
|
{
|
|
if (UIManager != null)
|
|
{
|
|
UIManager = Instantiate(UIManager);
|
|
Log.Info("User Interface Manager instantiated.");
|
|
}
|
|
else
|
|
{
|
|
Log.Error("User Interface Manager Prefab missing.");
|
|
}
|
|
if (ControlsManager != null)
|
|
{
|
|
ControlsManager = Instantiate(ControlsManager);
|
|
Log.Info("Controls Manager instantiated.");
|
|
}
|
|
else
|
|
{
|
|
Log.Error("Controls Manager Prefab missing.");
|
|
}
|
|
if (MatchManager != null)
|
|
{
|
|
MatchManager = Instantiate(MatchManager);
|
|
Log.Info("Match Manager instantiated.");
|
|
}
|
|
else
|
|
{
|
|
Log.Error("User Interface Manager Prefab missing.");
|
|
}
|
|
if (CharacterManager != null)
|
|
{
|
|
CharacterManager = Instantiate(CharacterManager);
|
|
Log.Info("Character Manager instantiated.");
|
|
}
|
|
else
|
|
{
|
|
Log.Error("Character Manager Prefab missing.");
|
|
}
|
|
if (PlayerManager != null)
|
|
{
|
|
PlayerManager = Instantiate(PlayerManager);
|
|
Log.Info("PlayerManager Manager instantiated.");
|
|
}
|
|
else
|
|
{
|
|
Log.Error("PlayerManager Manager Prefab missing.");
|
|
}
|
|
if (AudioManager != null)
|
|
{
|
|
AudioManager = Instantiate(AudioManager);
|
|
Log.Info("PlayerManager Manager instantiated.");
|
|
}
|
|
else
|
|
{
|
|
Log.Error("PlayerManager Manager Prefab missing.");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Starts the camera, for showing an image before the main menu is loaded.
|
|
/// </summary>
|
|
void ShowStartScreen()
|
|
{
|
|
startCamera.SetActive(true);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets up switching cameras once the menu is loaded
|
|
/// and starts the async scene loading.
|
|
/// </summary>
|
|
void LoadMainMenu()
|
|
{
|
|
SingleUseSceneLoadedMethodCaller((args) =>
|
|
{
|
|
SceneManager.SetActiveScene(args.SceneRef);
|
|
startCamera.SetActive(false);
|
|
}, Scenes.MainMenu);
|
|
SceneManager.LoadSceneAsync((int)Scenes.MainMenu, LoadSceneMode.Additive);
|
|
Log.Info("Main menu scene loaded.");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initiates a local battle by giving relavant information to the responsible managers
|
|
/// and starting their appropriate processes.
|
|
/// </summary>
|
|
/// <param name="sceneId">Scene id of the chosen arena.</param>
|
|
public IEnumerator SetupLocalMatchFromMainMenu()
|
|
{
|
|
MatchManager.LoadMatchRules(0);
|
|
MatchManager.LoadArenaProperties(0);
|
|
MatchManager.AssignMatchObjects();
|
|
PlayerManager.LocalMatchJoinPlayers(MatchManager.ArenaProperties.minPlayerCount);
|
|
// TODO: This is in place of a character choosing menu etc.
|
|
foreach (Player p in PlayerManager.MatchPlayers)
|
|
{
|
|
CharacterManager.AssignShipFixed(p);
|
|
Log.Debug($"Ship: {p.character.name} assigned to player: {p.playerNumber}.");
|
|
}
|
|
|
|
MatchManager.StartCharacterSelect();
|
|
CharacterManager.SpawnCharacters(PlayerManager.MatchPlayers);
|
|
|
|
UIManager.StartManagingMatchUI();
|
|
UIManager.AssignHUDElementsToPlayers(PlayerManager.MatchPlayers);
|
|
|
|
ControlsManager.AssignControlsToPlayers(PlayerManager.MatchPlayers);
|
|
|
|
UIManager.StartInputPrompt(ControlsManager.unassignedPlayers);
|
|
|
|
// Waits with starting the match until every player has controls
|
|
while (ControlsManager.unassignedPlayers.Count > 0)
|
|
{
|
|
yield return null;
|
|
}
|
|
MatchManager.StartMatch();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Starts a match scene without the menus or input/start prompts.
|
|
/// </summary>
|
|
/// <param name="scene">The match scene which will be loaded</param>
|
|
/// <returns></returns>
|
|
public IEnumerator SetupTestMatch(Scenes scene)
|
|
{
|
|
yield return null;
|
|
SceneManager.LoadScene((int)scene, LoadSceneMode.Additive);
|
|
yield return null;
|
|
SceneManager.LoadScene((int)Scenes.InGameUI, LoadSceneMode.Additive);
|
|
yield return null;
|
|
SceneManager.SetActiveScene(SceneManager.GetSceneByBuildIndex((int)scene));
|
|
yield return null;
|
|
MatchManager.LoadMatchRules(0);
|
|
MatchManager.LoadArenaProperties(0);
|
|
MatchManager.AssignMatchObjects();
|
|
PlayerManager.LocalMatchJoinPlayers(MatchManager.ArenaProperties.minPlayerCount);
|
|
foreach (Player p in PlayerManager.MatchPlayers)
|
|
{
|
|
CharacterManager.AssignShipFixed(p);
|
|
Log.Debug($"Ship: {p.character.name} assigned to player: {p.playerNumber}.");
|
|
}
|
|
MatchManager.StartCharacterSelect();
|
|
CharacterManager.SpawnCharacters(PlayerManager.MatchPlayers);
|
|
UIManager.StartManagingMatchUI();
|
|
UIManager.AssignHUDElementsToPlayers(PlayerManager.MatchPlayers);
|
|
ControlsManager.AssignControlsToPlayers(PlayerManager.MatchPlayers);
|
|
MatchManager.StartTestMatch();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initiates an online battle by giving relavant information to the responsible managers
|
|
/// and starting their appropriate processes.
|
|
/// </summary>
|
|
/// <param name="sceneId">Scene id of the chosen arena.</param>
|
|
public IEnumerator SetupOnlineMatchFromMainMenu()
|
|
{
|
|
MatchManager.LoadMatchRules(0);
|
|
MatchManager.LoadArenaProperties(0);
|
|
MatchManager.AssignMatchObjects();
|
|
// TODO: Selection for character in online play here
|
|
PlayerManager.LoadOnlinePlayer();
|
|
if (InstanceFinder.IsServerStarted)
|
|
CharacterManager.AssignShipFixed(PlayerManager.OnlinePlayer, 0);
|
|
else if (InstanceFinder.IsClientStarted)
|
|
CharacterManager.AssignShipFixed(PlayerManager.OnlinePlayer, 1);
|
|
Log.Debug($"Ship: {PlayerManager.OnlinePlayer.character.name} assigned to online player.");
|
|
|
|
CharacterManager.SpawnOnlineCharacter(PlayerManager.OnlinePlayer);
|
|
|
|
UIManager.StartManagingMatchUI();
|
|
UIManager.AssignHUDElementsToPlayers(PlayerManager.MatchPlayers);
|
|
|
|
ControlsManager.AssignControlsToPlayers(PlayerManager.MatchPlayers);
|
|
|
|
UIManager.StartInputPrompt(ControlsManager.unassignedPlayers);
|
|
|
|
// Waits with starting the match until every player has controls
|
|
while (ControlsManager.unassignedPlayers.Count > 0)
|
|
{
|
|
yield return null;
|
|
}
|
|
MatchManager.StartTestMatch();
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// Triggers a method once, when a specific scene was loaded.
|
|
/// </summary>
|
|
/// <param name="func">The method which will be executed
|
|
/// once the scene is loaded.</param>
|
|
/// <param name="sceneEnum">The scene which will trigger the method when loaded.</param>
|
|
public void SingleUseSceneLoadedMethodCaller(CustomOnSceneLoaded method, Scenes sceneEnum)
|
|
{
|
|
// This is used because SceneManager.sceneLoaded only passes ref and loadMode.
|
|
// I want add the sceneEnum to this, to check if the the sceneLoaded event
|
|
// refers to the same scene as passed to this method.
|
|
UnityAction<Scene, LoadSceneMode> OnSceneLoaded = (sceneRef, loadMode) =>
|
|
{
|
|
CustomSceneLoaded.Invoke(null, new SceneLoadEventArgs(sceneEnum, sceneRef));
|
|
};
|
|
|
|
EventHandler<SceneLoadEventArgs> handler = null;
|
|
|
|
handler = (invoker, args) =>
|
|
{
|
|
// Thanks to the CustomSceneLoaded event I can check this here.
|
|
if (args.SceneRef.buildIndex == (int)args.SceneEnum)
|
|
{
|
|
method(args);
|
|
}
|
|
else
|
|
{
|
|
Log.Warn("Should have loaded scene: " + args.SceneEnum.ToString() +
|
|
" but the most recently loaded scene is: " + args.SceneRef.name +
|
|
". Be careful of loading many scenes at once from different scripts!");
|
|
}
|
|
CustomSceneLoaded -= handler;
|
|
SceneManager.sceneLoaded -= OnSceneLoaded;
|
|
};
|
|
|
|
CustomSceneLoaded += handler;
|
|
|
|
SceneManager.sceneLoaded += OnSceneLoaded;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Loads all prefabs/gameobjects from a folder if the contain the given type
|
|
/// as a component and adds them to a list.
|
|
/// </summary>
|
|
/// <param name="path">Path of the folder</param>
|
|
/// <param name="prefabList">List the loaded prefabs will be added to</param>
|
|
public static void LoadPrefabsFromFolder<T>(string path, in List<GameObject> prefabList)
|
|
{
|
|
#if UNITY_EDITOR
|
|
string[] files = Directory.GetFiles(path, "*.prefab",
|
|
SearchOption.TopDirectoryOnly);
|
|
List<GameObject> gos = new List<GameObject>();
|
|
foreach (var file in files)
|
|
{
|
|
gos.Add(AssetDatabase.LoadAssetAtPath<GameObject>(file));
|
|
}
|
|
foreach (GameObject go in gos)
|
|
{
|
|
if (go.TryGetComponent<T>(out _))
|
|
{
|
|
prefabList.Add(go);
|
|
}
|
|
else
|
|
{
|
|
Log.Warn($"GameObject: {go.name} did not contain a {typeof(T).Name} component. It won't be added to the list.");
|
|
}
|
|
}
|
|
#else
|
|
Log.Error("Can only access prefabs in folders when in editor!");
|
|
#endif
|
|
}
|
|
|
|
/// <summary>
|
|
/// Loads all prefabs/gameobjects from an asset bundle if the contain the given type
|
|
/// as a component and adds them to a list.
|
|
/// TODO: DO NOT FORGET TO manually BUILD ASSET BUNDLES WHEN BUILDING
|
|
/// </summary>
|
|
/// <param name="name">Name of the asset bundle</param>
|
|
/// <param name="prefabList">List the loaded prefabs will be added to</param>
|
|
public static void LoadPrefabsFromBundle<T>(string name, in List<GameObject> prefabList)
|
|
{
|
|
var audioAssetBundle = AssetBundle.LoadFromFile(Path.Combine(Application.streamingAssetsPath, name));
|
|
if (audioAssetBundle == null)
|
|
{
|
|
Log.Error("Failed to load arenas asset bundle!");
|
|
return;
|
|
}
|
|
List<GameObject> gos = new List<GameObject>();
|
|
gos.AddRange(audioAssetBundle.LoadAllAssets<GameObject>());
|
|
|
|
foreach (GameObject go in gos)
|
|
{
|
|
if (go.TryGetComponent<T>(out _))
|
|
{
|
|
prefabList.Add(go);
|
|
}
|
|
else
|
|
{
|
|
Log.Warn($"GameObject: {go.name} did not contain a {typeof(T).Name} component. It won't be added to the list.");
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Loads all assets from a folder, if they are of the given type and adds them to a list.
|
|
/// </summary>
|
|
/// <param name="path">Path of the folder</param>
|
|
/// <param name="prefabList">List the loaded prefabs will be added to</param>
|
|
public static void LoadAssetsFromFolder<T>(string path, in List<T> prefabList)
|
|
where T : UnityEngine.Object
|
|
{
|
|
#if UNITY_EDITOR
|
|
string[] files = Directory.GetFiles(path, "*.asset",
|
|
SearchOption.TopDirectoryOnly);
|
|
foreach (var file in files)
|
|
{
|
|
prefabList.Add(AssetDatabase.LoadAssetAtPath<T>(file));
|
|
}
|
|
#else
|
|
Log.Error("Can only access prefabs in folders when in editor!");
|
|
#endif
|
|
}
|
|
|
|
/// <summary>
|
|
/// Loads all assets from an asset bundle, if they are of the given type and adds them to a list.
|
|
/// TODO: DO NOT FORGET TO manually BUILD ASSET BUNDLES WHEN BUILDING
|
|
/// </summary>
|
|
/// <param name="name">Name of the asset bundle</param>
|
|
/// <param name="prefabList">List the loaded prefabs will be added to</param>
|
|
public static void LoadAssetsFromBundle<T>(string name, in List<T> prefabList)
|
|
where T : UnityEngine.Object
|
|
{
|
|
var arenasAssetBundle = AssetBundle.LoadFromFile(Path.Combine(Application.streamingAssetsPath, name));
|
|
if (arenasAssetBundle == null)
|
|
{
|
|
Log.Error("Failed to load arenas asset bundle!");
|
|
return;
|
|
}
|
|
prefabList.AddRange(arenasAssetBundle.LoadAllAssets<T>());
|
|
}
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Custom delegate which can be executed after scene load.
|
|
/// </summary>
|
|
/// <param name="args">Data of the loaded scene</param>
|
|
public delegate void CustomOnSceneLoaded(SceneLoadEventArgs args);
|
|
|
|
public class SceneLoadEventArgs : EventArgs
|
|
{
|
|
public SceneLoadEventArgs(Scenes sceneEnum, Scene sceneRef)
|
|
{
|
|
SceneEnum = sceneEnum;
|
|
SceneRef = sceneRef;
|
|
}
|
|
public Scenes SceneEnum { get; set; }
|
|
public Scene SceneRef { get; set; }
|
|
}
|
|
|
|
} |