203 lines
6.1 KiB
C#
203 lines
6.1 KiB
C#
using PashaBibko.Pacore.Attributes;
|
|
using Unity.Netcode.Transports.UTP;
|
|
using UnityEngine.SceneManagement;
|
|
using System.Collections;
|
|
using Unity.Netcode;
|
|
using UnityEngine;
|
|
using System;
|
|
|
|
namespace PashaBibko.PenguinChase.Network
|
|
{
|
|
public enum TransportType
|
|
{
|
|
UnityRelay,
|
|
Localhost,
|
|
|
|
None
|
|
}
|
|
|
|
public interface INetworkTransport
|
|
{
|
|
public IEnumerator Join(string code, Action callback);
|
|
public IEnumerator Host(Action callback);
|
|
}
|
|
|
|
public class Network : MonoBehaviour
|
|
{
|
|
private static Network sInstance;
|
|
|
|
[Header("Transports")]
|
|
[SerializeField] private GameObject LocalHostTransport;
|
|
[SerializeField] private GameObject UnityRelayTransport;
|
|
|
|
[Header("View only")] [SerializeField, InspectorReadOnly]
|
|
private TransportType InternalCurrentTransport = TransportType.None;
|
|
|
|
public static TransportType CurrentTransport
|
|
{
|
|
get => sInstance?.InternalCurrentTransport ?? TransportType.None;
|
|
set => sInstance?.StartCoroutine(sInstance.ChangeTransport(value));
|
|
}
|
|
|
|
#if UNITY_EDITOR
|
|
[Header("Editor Only")]
|
|
[SerializeField] private string GameJoinCode;
|
|
#endif // UNITY_EDITOR
|
|
|
|
private static INetworkTransport sConnectionManager;
|
|
|
|
private GameObject mCurrentChildTransport;
|
|
private bool mSafeToConnect = true;
|
|
|
|
public static UnityTransport CurrentTransportComponent
|
|
{
|
|
get
|
|
{
|
|
UnityTransport component = null;
|
|
sInstance?.mCurrentChildTransport?.TryGetComponent(out component);
|
|
return component;
|
|
}
|
|
}
|
|
|
|
private void Awake()
|
|
{
|
|
// Stops overlapping instances
|
|
if (sInstance is not null)
|
|
{
|
|
Debug.LogError($"Multiple of [{nameof(Network)}] cannot exist.");
|
|
Destroy(gameObject);
|
|
return;
|
|
}
|
|
|
|
sInstance = this;
|
|
}
|
|
|
|
private IEnumerator HostInternal()
|
|
{
|
|
// Waits for it to be safe to connect, quits after 5 seconds
|
|
float timeout = 0f;
|
|
while (!mSafeToConnect)
|
|
{
|
|
if (timeout > 5f)
|
|
{
|
|
Debug.LogError("Host timed out");
|
|
yield break;
|
|
}
|
|
|
|
timeout += Time.deltaTime;
|
|
yield return null;
|
|
}
|
|
|
|
// Then actually hosts the lobby
|
|
yield return sConnectionManager.Host(() =>
|
|
{
|
|
NetworkManager.Singleton.SceneManager.LoadScene("LobbyScene", LoadSceneMode.Single);
|
|
Debug.Log("Hosted");
|
|
});
|
|
}
|
|
|
|
public static void Host()
|
|
{
|
|
if (sConnectionManager is null)
|
|
{
|
|
throw new InvalidOperationException("No connection manager has been set.");
|
|
}
|
|
|
|
if (sInstance is null)
|
|
{
|
|
throw new InvalidOperationException("No network manager has been set.");
|
|
}
|
|
|
|
sInstance.StartCoroutine(sInstance.HostInternal());
|
|
}
|
|
|
|
private IEnumerator JoinInternal(string code)
|
|
{
|
|
// Waits for it to be safe to connect, quits after 5 seconds
|
|
float timeout = 0f;
|
|
while (!mSafeToConnect)
|
|
{
|
|
if (timeout > 5f)
|
|
{
|
|
Debug.LogError("Host timed out");
|
|
yield break;
|
|
}
|
|
|
|
timeout += Time.deltaTime;
|
|
yield return null;
|
|
}
|
|
|
|
// Then connects to the lobby
|
|
yield return sConnectionManager.Join(code, () =>
|
|
{
|
|
Debug.Log($"Joined {code}");
|
|
});
|
|
}
|
|
|
|
public static void Join(string code)
|
|
{
|
|
if (sConnectionManager is null)
|
|
{
|
|
throw new InvalidOperationException("No connection manager has been set.");
|
|
}
|
|
|
|
if (sInstance is null)
|
|
{
|
|
throw new InvalidOperationException("No network manager has been set.");
|
|
}
|
|
|
|
sInstance.StartCoroutine(sInstance.JoinInternal(code));
|
|
}
|
|
|
|
private IEnumerator ChangeTransport(TransportType transport)
|
|
{
|
|
// Stops network from being restarted when unneeded
|
|
if (transport == InternalCurrentTransport)
|
|
{
|
|
yield break;
|
|
}
|
|
|
|
mSafeToConnect = false;
|
|
InternalCurrentTransport = transport;
|
|
|
|
// Shutdown existing network manager (if there is one) to stop multiple at once
|
|
if (NetworkManager.Singleton is not null)
|
|
{
|
|
NetworkManager.Singleton.Shutdown();
|
|
while (NetworkManager.Singleton.ShutdownInProgress)
|
|
{
|
|
yield return null; // Waits for next frame
|
|
}
|
|
|
|
Destroy(mCurrentChildTransport);
|
|
}
|
|
|
|
// Loads the new transport controller and lets it setup
|
|
switch (InternalCurrentTransport)
|
|
{
|
|
case TransportType.UnityRelay:
|
|
mCurrentChildTransport = Instantiate(UnityRelayTransport);
|
|
sConnectionManager = new UnityRelayTransport();
|
|
break;
|
|
|
|
case TransportType.Localhost:
|
|
mCurrentChildTransport = Instantiate(LocalHostTransport);
|
|
sConnectionManager = new LocalhostTransport();
|
|
break;
|
|
|
|
case TransportType.None:
|
|
// Nothing needs to be done here as there is no network controller
|
|
mCurrentChildTransport = null;
|
|
yield break;
|
|
|
|
default:
|
|
mSafeToConnect = true;
|
|
throw new ArgumentOutOfRangeException();
|
|
}
|
|
|
|
DontDestroyOnLoad(mCurrentChildTransport);
|
|
mSafeToConnect = true;
|
|
}
|
|
}
|
|
}
|