using System;
using System.Collections;
using System.IO;
using System.Reflection;
using System.Threading.Tasks;
using log4net;
using log4net.Config;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
///
/// The available scenes in the order they are in the build settings.
///
public enum Scenes
{
GameMangement,
MenuUserInterface,
GameplayUserInterface,
Arena,
}
namespace Managers
{
// public enum GameState { Starting, Match, End, Paused }
///
/// 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 ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
///
/// Globally accessible member to use manager with.
///
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 AVEffectsManager AVEffectsManager;
[SerializeField]
private GameObject startCamera;
public event EventHandler CustomSceneLoaded;
void Awake()
{
G = this;
ShowStartScreen();
ConfigureLog4Net();
Log.Info("Awake");
}
void Start()
{
InstantiateBaseManagers();
Log.Info("Space Smash Out is starting.");
LoadMainMenu();
}
///
/// Configuration of log 4 net, before the game starts.
///
void ConfigureLog4Net()
{
log4net.GlobalContext.Properties["LogFileName"] = $"{Application.dataPath}" +
"\\Logging\\SSOLog";
var fi = new FileInfo($"{Application.dataPath}" +
"\\Logging\\Log4NetConfiguration.xml");
XmlConfigurator.Configure(fi);
Log.Debug("Log4Net configured.");
}
///
/// Instantiates the managers needed to use the main menu.
///
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 (AVEffectsManager != null)
{
AVEffectsManager = Instantiate(AVEffectsManager);
Log.Info("PlayerManager Manager instantiated.");
}
else
{
Log.Error("PlayerManager Manager Prefab missing.");
}
}
void ShowStartScreen()
{
startCamera.SetActive(true);
}
///
/// Sets up switching cameras once the menu is loaded
/// and starts the async scene loading.
///
void LoadMainMenu()
{
SingleUseSceneLoadedMethodCaller((args) =>
{
SceneManager.SetActiveScene(args.SceneRef);
startCamera.SetActive(false);
}, Scenes.MenuUserInterface);
SceneManager.LoadSceneAsync((int)Scenes.MenuUserInterface, LoadSceneMode.Additive);
Log.Info("Main menu scene loaded.");
}
///
/// Initiates a local battle by giving relavant information to the match manager
/// and starting the match managers appropriate process.
///
/// Scene id of the chosen arena.
public IEnumerator SetupLocalMatchFromMainMenu()
{
MatchManager.LoadMatchRules(0);
MatchManager.LoadArenaProperties(0);
PlayerManager.LocalMatchJoinPlayers(MatchManager.arenaProperties.minPlayerCount);
// TODO: This is in place of a character choosing menu etc.
foreach (Player p in PlayerManager.localPlayers)
{
CharacterManager.AssignShipFixed(p);
Log.Debug($"Ship: {p.character.name} assigned to player: {p.playerNumber}.");
}
MatchManager.StartCharacterSelect();
MatchManager.SpawnCharacters(PlayerManager.localPlayers);
UIManager.StartManagingMatchUI();
UIManager.AssignHUDElementsToPlayers(PlayerManager.localPlayers);
ControlsManager.AssignControlsToPlayers(PlayerManager.localPlayers);
UIManager.StartInputPrompt(ControlsManager.unassignedPlayers);
// Waits with starting the match until every player has controls
while (ControlsManager.unassignedPlayers.Count > 0)
{
yield return null;
}
MatchManager.StartMatch();
}
///
/// Triggers a method once, when a specific scene was loaded.
///
/// The method which will be executed
/// once the scene is loaded.
/// The scene which will trigger the method when loaded.
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 OnSceneLoaded = (sceneRef, loadMode) =>
{
CustomSceneLoaded.Invoke(null, new SceneLoadEventArgs(sceneEnum, sceneRef));
};
EventHandler 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;
}
}
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; }
}
}