240 lines
8.2 KiB
C#
240 lines
8.2 KiB
C#
using FishNet.Connection;
|
|
using FishNet.Managing;
|
|
using FishNet.Managing.Logging;
|
|
using FishNet.Managing.Scened;
|
|
using FishNet.Transporting;
|
|
using FishNet.Utility;
|
|
using System.IO;
|
|
using UnityEngine;
|
|
using UnityEngine.SceneManagement;
|
|
using UnitySceneManager = UnityEngine.SceneManagement.SceneManager;
|
|
|
|
/// <summary>
|
|
/// Add to a NetworkManager object to change between Online and Offline scene based on connection states of the server or client.
|
|
/// </summary>
|
|
[AddComponentMenu("FishNet/Component/DefaultScene")]
|
|
public class DefaultScene : MonoBehaviour
|
|
{
|
|
|
|
#region Serialized.
|
|
[Tooltip("True to load the online scene as global, false to load it as connection.")]
|
|
[SerializeField]
|
|
private bool _useGlobalScenes = true;
|
|
/// <summary>
|
|
/// True to replace all scenes with the offline scene immediately.
|
|
/// </summary>
|
|
[Tooltip("True to replace all scenes with the offline scene immediately.")]
|
|
[SerializeField]
|
|
private bool _startInOffline;
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
[Tooltip("Scene to load when disconnected. Server and client will load this scene.")]
|
|
[SerializeField, Scene]
|
|
private string _offlineScene;
|
|
/// <summary>
|
|
/// Sets which offline scene to use.
|
|
/// </summary>
|
|
/// <param name="sceneName">Scene name to use as the offline scene.</param>
|
|
public void SetOfflineScene(string sceneName) => _offlineScene = sceneName;
|
|
/// <summary>
|
|
/// Scene to load when disconnected. Server and client will load this scene.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public string GetOfflineScene() => _offlineScene;
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
[Tooltip("Scene to load when connected. Server and client will load this scene.")]
|
|
[SerializeField, Scene]
|
|
private string _onlineScene;
|
|
/// <summary>
|
|
/// Sets which online scene to use.
|
|
/// </summary>
|
|
/// <param name="sceneName">Scene name to use as the online scene.</param>
|
|
public void SetOnlineScene(string sceneName) => _onlineScene = sceneName;
|
|
/// <summary>
|
|
/// Scene to load when connected. Server and client will load this scene.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public string GetOnlineScene() => _onlineScene;
|
|
/// <summary>
|
|
/// Which scenes to replace when loading into OnlineScene.
|
|
/// </summary>
|
|
[Tooltip("Which scenes to replace when loading into OnlineScene.")]
|
|
[SerializeField]
|
|
private ReplaceOption _replaceScenes = ReplaceOption.All;
|
|
#endregion
|
|
|
|
#region Private.
|
|
/// <summary>
|
|
/// NetworkManager for this component.
|
|
/// </summary>
|
|
private NetworkManager _networkManager;
|
|
#endregion
|
|
|
|
private void Awake()
|
|
{
|
|
InitializeOnce();
|
|
}
|
|
|
|
private void OnDestroy()
|
|
{
|
|
|
|
if (!ApplicationState.IsQuitting() && _networkManager != null && _networkManager.Initialized)
|
|
{
|
|
_networkManager.ClientManager.OnClientConnectionState -= ClientManager_OnClientConnectionState;
|
|
_networkManager.ServerManager.OnServerConnectionState -= ServerManager_OnServerConnectionState;
|
|
_networkManager.SceneManager.OnLoadEnd -= SceneManager_OnLoadEnd;
|
|
_networkManager.ServerManager.OnAuthenticationResult -= ServerManager_OnAuthenticationResult;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes this script for use.
|
|
/// </summary>
|
|
private void InitializeOnce()
|
|
{
|
|
_networkManager = GetComponentInParent<NetworkManager>();
|
|
if (_networkManager == null)
|
|
{
|
|
|
|
NetworkManager.StaticLogError($"NetworkManager not found on {gameObject.name} or any parent objects. DefaultScene will not work.");
|
|
return;
|
|
}
|
|
//A NetworkManager won't be initialized if it's being destroyed.
|
|
if (!_networkManager.Initialized)
|
|
return;
|
|
if (_onlineScene == string.Empty || _offlineScene == string.Empty)
|
|
{
|
|
|
|
NetworkManager.StaticLogWarning("Online or Offline scene is not specified. Default scenes will not load.");
|
|
return;
|
|
}
|
|
|
|
_networkManager.ClientManager.OnClientConnectionState += ClientManager_OnClientConnectionState;
|
|
_networkManager.ServerManager.OnServerConnectionState += ServerManager_OnServerConnectionState;
|
|
_networkManager.SceneManager.OnLoadEnd += SceneManager_OnLoadEnd;
|
|
_networkManager.ServerManager.OnAuthenticationResult += ServerManager_OnAuthenticationResult;
|
|
if (_startInOffline)
|
|
LoadOfflineScene();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called when a scene load ends.
|
|
/// </summary>
|
|
private void SceneManager_OnLoadEnd(SceneLoadEndEventArgs obj)
|
|
{
|
|
bool onlineLoaded = false;
|
|
foreach (Scene s in obj.LoadedScenes)
|
|
{
|
|
if (s.name == GetSceneName(_onlineScene))
|
|
{
|
|
onlineLoaded = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//If online scene was loaded then unload offline.
|
|
if (onlineLoaded)
|
|
UnloadOfflineScene();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called after the local server connection state changes.
|
|
/// </summary>
|
|
private void ServerManager_OnServerConnectionState(ServerConnectionStateArgs obj)
|
|
{
|
|
/* When server starts load online scene as global.
|
|
* Since this is a global scene clients will automatically
|
|
* join it when connecting. */
|
|
if (obj.ConnectionState == LocalConnectionState.Started)
|
|
{
|
|
/* If not exactly one server is started then
|
|
* that means either none are started, which isnt true because
|
|
* we just got a started callback, or two+ are started.
|
|
* When a server has already started there's no reason to load
|
|
* scenes again. */
|
|
if (!_networkManager.ServerManager.OneServerStarted())
|
|
return;
|
|
|
|
//If here can load scene.
|
|
SceneLoadData sld = new SceneLoadData(GetSceneName(_onlineScene));
|
|
sld.ReplaceScenes = _replaceScenes;
|
|
if (_useGlobalScenes)
|
|
_networkManager.SceneManager.LoadGlobalScenes(sld);
|
|
else
|
|
_networkManager.SceneManager.LoadConnectionScenes(sld);
|
|
}
|
|
//When server stops load offline scene.
|
|
else if (obj.ConnectionState == LocalConnectionState.Stopped)
|
|
{
|
|
LoadOfflineScene();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called after the local client connection state changes.
|
|
/// </summary>
|
|
private void ClientManager_OnClientConnectionState(ClientConnectionStateArgs obj)
|
|
{
|
|
if (obj.ConnectionState == LocalConnectionState.Stopped)
|
|
{
|
|
//Only load offline scene if not also server.
|
|
if (!_networkManager.IsServer)
|
|
LoadOfflineScene();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called when a client completes authentication.
|
|
/// </summary>
|
|
private void ServerManager_OnAuthenticationResult(NetworkConnection arg1, bool authenticated)
|
|
{
|
|
/* This is only for loading connection scenes.
|
|
* If using global there is no need to continue. */
|
|
if (_useGlobalScenes)
|
|
return;
|
|
if (!authenticated)
|
|
return;
|
|
|
|
SceneLoadData sld = new SceneLoadData(GetSceneName(_onlineScene));
|
|
_networkManager.SceneManager.LoadConnectionScenes(arg1, sld);
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Loads offlineScene as single.
|
|
/// </summary>
|
|
private void LoadOfflineScene()
|
|
{
|
|
//Already in offline scene.
|
|
if (UnitySceneManager.GetActiveScene().name == GetSceneName(_offlineScene))
|
|
return;
|
|
//Only use scene manager if networking scenes. I may add something in later to do both local and networked.
|
|
UnitySceneManager.LoadScene(_offlineScene);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Unloads the offline scene.
|
|
/// </summary>
|
|
private void UnloadOfflineScene()
|
|
{
|
|
Scene s = UnitySceneManager.GetSceneByName(GetSceneName(_offlineScene));
|
|
if (string.IsNullOrEmpty(s.name))
|
|
return;
|
|
|
|
UnitySceneManager.UnloadSceneAsync(s);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns a scene name from fullPath.
|
|
/// </summary>
|
|
/// <param name="fullPath"></param>
|
|
/// <returns></returns>
|
|
private string GetSceneName(string fullPath)
|
|
{
|
|
return Path.GetFileNameWithoutExtension(fullPath);
|
|
}
|
|
}
|