using System; using System.Collections.Generic; using System.Threading.Tasks; using System.Linq; using Fusion; using Fusion.Sockets; using UnityEngine; using UnityEngine.SceneManagement; using Random = UnityEngine.Random; // Struct input đồng bộ giữa Spawner, Movement và StateMachine public struct PlayerInputData : INetworkInput { public Vector2 Direction; public Quaternion rot; public bool sprint; } public class BasicSpawner : MonoBehaviour, INetworkRunnerCallbacks { private NetworkRunner _runner; private string _roomName = "Room1"; public LobbyManager LobbyManager; [SerializeField] private NetworkPrefabRef _playerPrefab; private Dictionary _spawnedCharacters = new Dictionary(); // Thông tin profile local public PlayerProfile LocalPlayerProfile { get; private set; } public void SetLocalPlayerProfile(PlayerProfile profile) { LocalPlayerProfile = profile; } private void Awake() { if (_runner == null) _runner = gameObject.AddComponent(); DontDestroyOnLoad(gameObject); } // Khởi tạo Game (Host/Client) public async Task StartGame(GameMode mode, string sessionName = "TestRoom") { Debug.Log($"Fusion: Đang khởi tạo kết nối với Mode: {mode} | Phòng: {sessionName}"); if (_runner == null) _runner = gameObject.AddComponent(); _runner.ProvideInput = true; var sceneManager = gameObject.GetComponent(); if (sceneManager == null) sceneManager = gameObject.AddComponent(); var result = await _runner.StartGame(new StartGameArgs() { GameMode = mode, SessionName = sessionName, Scene = SceneRef.FromIndex(1), SceneManager = sceneManager }); if (result.Ok) { Debug.Log($"Fusion thành công: Đã vào phòng {sessionName}"); } else { Debug.LogError($"Fusion thất bại: Lý do: {result.ShutdownReason}"); if (_runner != null) { Destroy(_runner); _runner = null; } } } private void OnGUI() { if (_runner == null || !_runner.IsRunning) { float width = 400; float height = 300; float x = (Screen.width - width) / 2f; float y = (Screen.height - height) / 2f; GUI.Box(new Rect(x, y, width, height), "FUSION MULTIPLAYER"); float innerX = x + 20; float innerY = y + 40; float contentWidth = width - 40; GUI.Label(new Rect(innerX, innerY, 100, 30), "Tên phòng:"); _roomName = GUI.TextField(new Rect(innerX + 100, innerY, contentWidth - 100, 30), _roomName); if (GUI.Button(new Rect(innerX, innerY + 50, contentWidth, 60), "VÀO PHÒNG\n(Tự động Host/Client)")) { _ = StartGame(GameMode.AutoHostOrClient, _roomName); } if (GUI.Button(new Rect(innerX, innerY + 120, (contentWidth / 2) - 5, 50), "Tạo phòng\n(Host)")) { _ = StartGame(GameMode.Host, _roomName); } if (GUI.Button(new Rect(innerX + (contentWidth / 2) + 5, innerY + 120, (contentWidth / 2) - 5, 50), "Tham gia\n(Client)")) { _ = StartGame(GameMode.Client, _roomName); } GUI.Label(new Rect(innerX, innerY + 180, contentWidth, 50), "Gợi ý: Nhập cùng tên phòng để chơi chung.\nNếu phòng chưa có, máy sẽ tự tạo mới."); } else { string region = (_runner.SessionInfo != null && _runner.SessionInfo.IsValid) ? _runner.SessionInfo.Region : "Connecting..."; int playerCount = 0; foreach (var p in _runner.ActivePlayers) playerCount++; string info = $"Mode: {_runner.GameMode} | Region: {region} | Players: {playerCount}"; GUI.Box(new Rect(10, 10, 400, 30), info); if (GUI.Button(new Rect(10, 50, 100, 30), "Thoát")) { _runner.Shutdown(); } } } public void OnPlayerJoined(NetworkRunner runner, PlayerRef player) { if (runner.IsServer) { Vector3 spawnPosition = new Vector3(Random.Range(-10f, 10f), 2f, Random.Range(-10f, 10f)); spawnPosition += new Vector3(player.RawEncoded % 3, 0, player.RawEncoded % 3); var networkPlayerObject = runner.Spawn(_playerPrefab, spawnPosition, Quaternion.identity, player); runner.SetPlayerObject(player, networkPlayerObject); _spawnedCharacters.Add(player, networkPlayerObject); } } public void OnPlayerLeft(NetworkRunner runner, PlayerRef player) { if (_spawnedCharacters.TryGetValue(player, out NetworkObject networkObject)) { if (networkObject != null) runner.Despawn(networkObject); _spawnedCharacters.Remove(player); } } public void OnInput(NetworkRunner runner, NetworkInput input) { var data = new PlayerInputData(); // ĐỌC TRỰC TIẾP: Không dùng Buffer để tránh bị trôi phím data.Direction = new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical")); data.sprint = Input.GetKey(KeyCode.LeftShift); if (OnlyScove.Scripts.PlayerStateMachine.Local != null) { var sm = OnlyScove.Scripts.PlayerStateMachine.Local; if (sm.Cam != null) data.rot = sm.Cam.PlanarRotation; else data.rot = sm.NetworkedCameraRotation; } input.Set(data); } public void OnSessionListUpdated(NetworkRunner runner, List sessionList) { if (LobbyManager != null) LobbyManager.DisplayRoomList(sessionList); // UI.UIEventBus.TriggerRoomListUpdate(); } public void OnInputMissing(NetworkRunner runner, PlayerRef player, NetworkInput input) { } public void OnShutdown(NetworkRunner runner, ShutdownReason shutdownReason) { } public void OnConnectedToServer(NetworkRunner runner) { } public void OnDisconnectedFromServer(NetworkRunner runner, NetDisconnectReason reason) { } public void OnConnectRequest(NetworkRunner runner, NetworkRunnerCallbackArgs.ConnectRequest request, byte[] token) { } public void OnConnectFailed(NetworkRunner runner, NetAddress remoteAddress, NetConnectFailedReason reason) { } public void OnUserSimulationMessage(NetworkRunner runner, SimulationMessagePtr message) { } public void OnCustomAuthenticationResponse(NetworkRunner runner, Dictionary data) { } public void OnHostMigration(NetworkRunner runner, HostMigrationToken hostMigrationToken) { } public void OnSceneLoadDone(NetworkRunner runner) { } public void OnSceneLoadStart(NetworkRunner runner) { } public void OnObjectExitAOI(NetworkRunner runner, NetworkObject obj, PlayerRef player) { } public void OnObjectEnterAOI(NetworkRunner runner, NetworkObject obj, PlayerRef player) { } public void OnReliableDataReceived(NetworkRunner runner, PlayerRef player, ReliableKey key, ArraySegment data) { } public void OnReliableDataProgress(NetworkRunner runner, PlayerRef player, ReliableKey key, float progress) { } }