You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Driftology/Assets/Scripts/FusionLauncher.cs

365 lines
12 KiB
C#

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using Fusion;
using Fusion.Sockets;
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.SceneManagement;
using TMPro;
using UnityEngine.UI;
using System.Linq;
public class FusionLauncher : MonoBehaviour, INetworkRunnerCallbacks
{
[Header("Network Runner (Drag NOTHING here)")]
public NetworkRunner runner; // we'll create/destroy this at runtime
[Header("Lobby UI")]
public GameObject lobbyUI;
public SessionListUIHandler sessionListUIHandler;
public TMP_InputField lobbyNameInput;
public Button createLobbyButton;
public TextMeshProUGUI waitingText;
[Header("Player Prefab")]
public NetworkPrefabRef playerPrefab;
private Coroutine refreshCoroutine;
private int playerCount = 0;
private const int maxPlayers = 2;
private bool gameplayLoaded = false;
private bool connectedToServer = false;
void Awake()
{
// Ensure this launcher persists across loads
if (FindObjectsOfType<FusionLauncher>().Length > 1)
{
Destroy(gameObject);
return;
}
DontDestroyOnLoad(gameObject);
}
void Start()
{
// Kick off our dummy runner purely in client/browse mode:
StartDummyRunner();
// UI hookups
if (lobbyNameInput != null) lobbyNameInput.onValueChanged.AddListener(OnLobbyNameChanged);
OnLobbyNameChanged(lobbyNameInput.text);
waitingText.gameObject.SetActive(false);
// Start periodic lobby refresh once connected
refreshCoroutine = StartCoroutine(AutoRefreshLobbyList());
}
void OnDestroy()
{
if (refreshCoroutine != null)
StopCoroutine(refreshCoroutine);
}
IEnumerator AutoRefreshLobbyList()
{
while (true)
{
RefreshLobbyList();
yield return new WaitForSeconds(5f);
}
}
void OnLobbyNameChanged(string s)
{
createLobbyButton.interactable = !string.IsNullOrWhiteSpace(s) && s.Length <= 15;
}
// —————— DUMMY RUNNER ——————
// Starts a runner in CLIENT mode so we can list sessions.
async void StartDummyRunner()
{
// If already up & running, just bail.
if (runner != null && runner.IsRunning)
return;
// Ensure any old runner is cleared
await EnsureFreshRunner();
// Start as CLIENT
var result = await runner.StartGame(new StartGameArgs()
{
GameMode = GameMode.Client,
SceneManager = runner.gameObject.AddComponent<NetworkSceneManagerDefault>()
});
if (result.Ok)
{
Debug.Log("✅ Browser runner connected (Client mode).");
connectedToServer = true;
}
else if (result.ShutdownReason == ShutdownReason.GameNotFound)
{
Debug.Log(" No lobbies yet—but browser runner is live.");
connectedToServer = true;
}
else
{
Debug.LogError($"❌ Browser runner failed: {result.ShutdownReason}");
}
}
// —————— RESET / CREATE FRESH RUNNER ——————
private async Task EnsureFreshRunner()
{
// — Teardown any existing runner —
playerCount = 0;
gameplayLoaded = false;
connectedToServer = false;
if (runner != null && runner.IsRunning)
{
await runner.Shutdown();
Destroy(runner.gameObject);
}
if (refreshCoroutine != null)
{
StopCoroutine(refreshCoroutine);
refreshCoroutine = null;
}
// — Build a new runner GameObject —
var go = new GameObject("NetworkRunnerGO");
DontDestroyOnLoad(go);
// 1) Add the NetworkRunner
runner = go.AddComponent<NetworkRunner>();
// 2) Enable input collection BEFORE StartGame
runner.ProvideInput = true;
// 3) Register this launchers callbacks
runner.AddCallbacks(this);
// 4) Attach & register your FusionInputProvider
var inputProv = go.AddComponent<FusionInputProvider>();
runner.AddCallbacks(inputProv);
// 5) Log out what weve done
Debug.Log($"[Launcher] Spawned {go.name} → ProvideInput={runner.ProvideInput}; " +
$"FusionInputProvider attached");
// Note: we dont call StartGame here. That happens in CreateLobby() / JoinLobby().
}
//private async Task EnsureFreshRunner()
//{
// // Reset flags
// playerCount = 0;
// gameplayLoaded = false;
// connectedToServer = false;
// // If an old runner exists & is running, shut it down & destroy its GO
// if (runner != null && runner.IsRunning)
// {
// await runner.Shutdown();
// Destroy(runner.gameObject);
// }
// // Stop auto-refresh while we rebuild
// if (refreshCoroutine != null)
// {
// StopCoroutine(refreshCoroutine);
// refreshCoroutine = null;
// }
// // Make brand-new runner GameObject
// var go = new GameObject("NetworkRunnerGO");
// DontDestroyOnLoad(go); // keep it alive across scenes
// runner = go.AddComponent<NetworkRunner>();
// var inputProv = go.AddComponent<FusionInputProvider>();
// runner.AddCallbacks(inputProv);
// Debug.Log("✔️ Added FusionInputProvider AND registered it on " + go.name);
// // 3) Tell Fusion well be providing input
// runner.ProvideInput = true;
// // 4) Register your launcher callbacks
// runner.AddCallbacks(this);
//}
// —————— CREATE LOBBY (Host) ——————
public async void CreateLobby()
{
var name = lobbyNameInput.text.Trim();
if (string.IsNullOrEmpty(name))
{
Debug.LogWarning("Empty lobby name!");
return;
}
// Tear down browse runner & spawn a fresh one
await EnsureFreshRunner();
var sceneRef = SceneRef.FromIndex(SceneManager.GetActiveScene().buildIndex);
var res = await runner.StartGame(new StartGameArgs()
{
GameMode = GameMode.Host,
SessionName = name,
PlayerCount = maxPlayers,
Scene = sceneRef,
SceneManager = runner.gameObject.AddComponent<NetworkSceneManagerDefault>()
});
if (res.Ok)
{
Debug.Log($"✔ Hosted Lobby '{name}'");
lobbyUI.SetActive(false);
waitingText.text = "Waiting for player 2…";
waitingText.gameObject.SetActive(true);
}
else
{
Debug.LogError($"✖ Host failed: {res.ShutdownReason}");
}
}
// —————— JOIN LOBBY (Client) ——————
public async void JoinLobby(SessionInfo info)
{
// Tear down browse runner & spawn a fresh one
await EnsureFreshRunner();
var res = await runner.StartGame(new StartGameArgs()
{
GameMode = GameMode.Client,
SessionName = info.Name,
Scene = SceneRef.FromIndex(SceneManager.GetActiveScene().buildIndex),
SceneManager = runner.gameObject.AddComponent<NetworkSceneManagerDefault>()
});
if (res.Ok)
{
Debug.Log($"✔ Joined Lobby '{info.Name}'");
lobbyUI.SetActive(false);
waitingText.text = "Waiting for host…";
waitingText.gameObject.SetActive(true);
}
else
{
Debug.LogError($"✖ Join failed: {res.ShutdownReason}");
}
}
// —————— REFRESH LOBBY LIST ——————
public void RefreshLobbyList()
{
if (!connectedToServer) return;
//sessionListUIHandler.ClearList();
runner.JoinSessionLobby(SessionLobby.ClientServer);
}
// —————— FUSION CALLBACKS ——————
public void OnConnectedToServer(NetworkRunner r)
{
connectedToServer = true;
Debug.Log("✔ Connected to server; can refresh lobbies.");
RefreshLobbyList();
}
public void OnSessionListUpdated(NetworkRunner runner, List<SessionInfo> sessionList)
{
// First thing, wipe out the old items every time
sessionListUIHandler.ClearList();
// If there really are no sessions, show your “no sessions” message
if (sessionList.Count == 0)
{
sessionListUIHandler.ShowNoSessionsMessage();
return;
}
// Otherwise re-populate
foreach (var session in sessionList)
{
if (session.IsOpen && session.IsVisible && session.PlayerCount < session.MaxPlayers)
{
sessionListUIHandler.AddToList(session, JoinLobby);
}
}
}
public void OnPlayerJoined(NetworkRunner r, PlayerRef p)
{
playerCount++;
// Only the host in Gameplay scene spawns cars
//if (r.IsServer && SceneManager.GetActiveScene().name == "Gameplay")
//{
// var pos = new Vector3(Random.Range(-5, 5), 0, Random.Range(-5, 5));
// r.Spawn(playerPrefab, pos, Quaternion.identity, p);
//}
// Only the host triggers sceneload when 2 players are present
if (r.IsServer && playerCount == maxPlayers && !gameplayLoaded)
{
gameplayLoaded = true;
var scene = SceneRef.FromIndex(
SceneUtility.GetBuildIndexByScenePath("Assets/Scenes/Gameplay.unity")
);
r.LoadScene(scene, LoadSceneMode.Single);
waitingText.gameObject.SetActive(false);
}
}
public void OnSceneLoadDone(NetworkRunner runner)
{
if (!runner.IsServer) return;
// only run once per game start
if (gameplayLoaded)
{
gameplayLoaded = false;
// grab your provider
var provider = FindObjectOfType<SpawnPointProvider>();
if (provider == null || provider.spawnPoints == null || provider.spawnPoints.Length == 0)
{
Debug.LogError("No SpawnPointProvider or no spawnPoints assigned!");
return;
}
// convert the IEnumerable to an array
PlayerRef[] players = runner.ActivePlayers.ToArray();
// pick the smaller of (number of players) vs (number of spawnPoints)
int count = Mathf.Min(players.Length, provider.spawnPoints.Length);
for (int i = 0; i < count; i++)
{
PlayerRef p = players[i];
Transform sp = provider.spawnPoints[i];
runner.Spawn(playerPrefab, sp.position, sp.rotation, p);
Debug.Log("SpawnPoints done: "+i);
}
}
}
public void OnDisconnectedFromServer(NetworkRunner r, NetDisconnectReason reason) { }
public void OnConnectRequest(NetworkRunner r, NetworkRunnerCallbackArgs.ConnectRequest req, byte[] tok) { }
public void OnConnectFailed(NetworkRunner r, NetAddress addr, NetConnectFailedReason reason) { }
public void OnUserSimulationMessage(NetworkRunner r, SimulationMessagePtr msg) { }
public void OnShutdown(NetworkRunner r, ShutdownReason reason) { }
public void OnPlayerLeft(NetworkRunner r, PlayerRef p) { }
public void OnInput(NetworkRunner r, NetworkInput input) { }
public void OnInputMissing(NetworkRunner r, PlayerRef p, NetworkInput input) { }
public void OnObjectEnterAOI(NetworkRunner r, NetworkObject obj, PlayerRef p) { }
public void OnObjectExitAOI(NetworkRunner r, NetworkObject obj, PlayerRef p) { }
public void OnReliableDataReceived(NetworkRunner r, PlayerRef p, ReliableKey k, System.ArraySegment<byte> data) { }
public void OnReliableDataProgress(NetworkRunner r, PlayerRef p, ReliableKey k, float prog) { }
//public void OnSceneLoadDone(NetworkRunner r) { }
public void OnSceneLoadStart(NetworkRunner r) { }
public void OnHostMigration(NetworkRunner r, HostMigrationToken t) { }
public void OnCustomAuthenticationResponse(NetworkRunner r, Dictionary<string, object> data) { }
}