using Unity.Netcode; using UnityEngine; #if ENABLE_INPUT_SYSTEM using UnityEngine.InputSystem; #endif /// /// Dev-only connection harness for local multiplayer testing across the junction-mirror clones: /// pick a role (Hunter/Hider) in the panel, then one instance clicks Host and the others click /// Client (loopback 127.0.0.1 via the configured UnityTransport). The chosen role rides along as the /// connection-approval payload, so the server spawns that role's prefab variant for the connection. /// Hotkeys: H = Host, C = Client, J = Server, K = Shutdown. Purely a testing scaffold - replace with /// real lobby/menu UI later. Attach to the same GameObject as the NetworkManager. /// [RequireComponent(typeof(NetworkManager))] [DisallowMultipleComponent] public class NetworkBootstrap : MonoBehaviour { [Tooltip("Draw the on-screen Host/Client panel (top-left).")] public bool showGui = true; [Tooltip("Allow the H/C/J/K keyboard shortcuts.")] public bool enableHotkeys = true; [Header("Role prefabs")] [Tooltip("Prefab spawned for a connection that picked Hunter. Must be registered as a network prefab.")] [SerializeField] private GameObject hunterPrefab; [Tooltip("Prefab spawned for a connection that picked Hider. Must be registered as a network prefab.")] [SerializeField] private GameObject hiderPrefab; [Tooltip("Role this instance connects as. Toggle it in the dev panel before hosting/joining.")] [SerializeField] private PlayerRole selectedRole = PlayerRole.Hider; private NetworkManager _net; private void Awake() { _net = GetComponent(); // Per-connection prefab selection needs connection approval: the callback maps the role byte // the joiner sent to the matching prefab hash. Enabled here so the scene asset needn't carry it. _net.NetworkConfig.ConnectionApproval = true; _net.ConnectionApprovalCallback = ApprovalCheck; } /// Stamps the chosen role into the connection payload, then starts the given mode. /// StartHost runs approval on its own client too, so the host's role is read from this same payload. private void StartAs(System.Func start) { _net.NetworkConfig.ConnectionData = new[] { (byte)selectedRole }; start(); } private void ApprovalCheck(NetworkManager.ConnectionApprovalRequest request, NetworkManager.ConnectionApprovalResponse response) { PlayerRole role = (request.Payload != null && request.Payload.Length > 0) ? (PlayerRole)request.Payload[0] : PlayerRole.Hider; GameObject prefab = role == PlayerRole.Hunter ? hunterPrefab : hiderPrefab; var netObj = prefab ? prefab.GetComponent() : null; response.Approved = true; response.CreatePlayerObject = true; // Null prefab/ref falls back to the NetworkManager's default PlayerPrefab. if (netObj) response.PlayerPrefabHash = netObj.PrefabIdHash; } private void Update() { if (!enableHotkeys) return; #if ENABLE_INPUT_SYSTEM var kb = Keyboard.current; if (kb == null || _net == null) return; if (!_net.IsListening) { if (kb.hKey.wasPressedThisFrame) StartAs(_net.StartHost); else if (kb.cKey.wasPressedThisFrame) StartAs(_net.StartClient); else if (kb.jKey.wasPressedThisFrame) StartAs(_net.StartServer); } else if (kb.kKey.wasPressedThisFrame) { _net.Shutdown(); } #endif } private void OnGUI() { if (!showGui || _net == null) return; GUILayout.BeginArea(new Rect(10, 10, 220, 200), GUI.skin.box); if (!_net.IsListening) { GUILayout.Label("Netcode (dev)"); GUILayout.BeginHorizontal(); GUILayout.Label("Role:", GUILayout.Width(38)); if (GUILayout.Toggle(selectedRole == PlayerRole.Hider, "Hider", GUI.skin.button)) selectedRole = PlayerRole.Hider; if (GUILayout.Toggle(selectedRole == PlayerRole.Hunter, "Hunter", GUI.skin.button)) selectedRole = PlayerRole.Hunter; GUILayout.EndHorizontal(); if (GUILayout.Button("Host (H)")) StartAs(_net.StartHost); if (GUILayout.Button("Client (C)")) StartAs(_net.StartClient); if (GUILayout.Button("Server (J)")) StartAs(_net.StartServer); } else { string role = _net.IsHost ? "Host" : _net.IsServer ? "Server" : "Client"; GUILayout.Label($"Role: {role} ({selectedRole})"); GUILayout.Label($"ClientId: {_net.LocalClientId}"); GUILayout.Label($"Clients: {(_net.IsServer ? _net.ConnectedClients.Count : (_net.IsConnectedClient ? 1 : 0))}"); if (GUILayout.Button("Shutdown (K)")) _net.Shutdown(); } GUILayout.EndArea(); } }