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#

using Fusion;
using Fusion.Sockets;
2 months ago
using System.Collections;
using System.Collections.Generic;
2 months ago
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.SceneManagement;
2 months ago
using TMPro;
using UnityEngine.UI;
2 months ago
using System.Linq;
public class FusionLauncher : MonoBehaviour, INetworkRunnerCallbacks
{
2 months ago
[Header("Network Runner (Drag NOTHING here)")]
public NetworkRunner runner; // we'll create/destroy this at runtime
[Header("Lobby UI")]
public GameObject lobbyUI;
2 months ago
public SessionListUIHandler sessionListUIHandler;
public TMP_InputField lobbyNameInput;
public Button createLobbyButton;
public TextMeshProUGUI waitingText;
2 months ago
[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()
{
2 months ago
while (true)
{
2 months ago
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;
2 months ago
// 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;
2 months ago
if (runner != null && runner.IsRunning)
{
await runner.Shutdown();
Destroy(runner.gameObject);
}
if (refreshCoroutine != null)
{
StopCoroutine(refreshCoroutine);
refreshCoroutine = null;
}
// — Build a new runner GameObject —
2 months ago
var go = new GameObject("NetworkRunnerGO");
DontDestroyOnLoad(go);
2 months ago
// 1) Add the NetworkRunner
2 months ago
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);
//}
2 months ago
// —————— CREATE LOBBY (Host) ——————
public async void CreateLobby()
{
2 months ago
var name = lobbyNameInput.text.Trim();
if (string.IsNullOrEmpty(name))
{
Debug.LogWarning("Empty lobby name!");
2 months ago
return;
}
// Tear down browse runner & spawn a fresh one
2 months ago
await EnsureFreshRunner();
var sceneRef = SceneRef.FromIndex(SceneManager.GetActiveScene().buildIndex);
2 months ago
var res = await runner.StartGame(new StartGameArgs()
{
GameMode = GameMode.Host,
2 months ago
SessionName = name,
PlayerCount = maxPlayers,
Scene = sceneRef,
2 months ago
SceneManager = runner.gameObject.AddComponent<NetworkSceneManagerDefault>()
});
2 months ago
if (res.Ok)
{
Debug.Log($"✔ Hosted Lobby '{name}'");
lobbyUI.SetActive(false);
2 months ago
waitingText.text = "Waiting for player 2…";
waitingText.gameObject.SetActive(true);
}
else
{
Debug.LogError($"✖ Host failed: {res.ShutdownReason}");
}
}
2 months ago
// —————— JOIN LOBBY (Client) ——————
public async void JoinLobby(SessionInfo info)
{
2 months ago
// Tear down browse runner & spawn a fresh one
await EnsureFreshRunner();
var res = await runner.StartGame(new StartGameArgs()
{
GameMode = GameMode.Client,
2 months ago
SessionName = info.Name,
Scene = SceneRef.FromIndex(SceneManager.GetActiveScene().buildIndex),
2 months ago
SceneManager = runner.gameObject.AddComponent<NetworkSceneManagerDefault>()
});
2 months ago
if (res.Ok)
{
2 months ago
Debug.Log($"✔ Joined Lobby '{info.Name}'");
lobbyUI.SetActive(false);
2 months ago
waitingText.text = "Waiting for host…";
waitingText.gameObject.SetActive(true);
}
else
{
2 months ago
Debug.LogError($"✖ Join failed: {res.ShutdownReason}");
}
}
// —————— REFRESH LOBBY LIST ——————
public void RefreshLobbyList()
{
if (!connectedToServer) return;
//sessionListUIHandler.ClearList();
runner.JoinSessionLobby(SessionLobby.ClientServer);
}
2 months ago
// —————— 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)
{
2 months ago
// 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)
{
2 months ago
sessionListUIHandler.ShowNoSessionsMessage();
return;
}
2 months ago
// Otherwise re-populate
foreach (var session in sessionList)
{
if (session.IsOpen && session.IsVisible && session.PlayerCount < session.MaxPlayers)
{
2 months ago
sessionListUIHandler.AddToList(session, JoinLobby);
}
}
}
2 months ago
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);
2 months ago
}
}
}
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) { }
}