using UnityEditor; using UnityEditor.SceneManagement; using UnityEngine; using UnityEngine.UI; using TMPro; using Unity.Netcode; using Unity.Netcode.Transports.UTP; namespace Colosseum.Editor { public static class LobbySceneBuilder { [MenuItem("Colosseum/Build Lobby Scene")] public static void Build() { // ── 씬 생성 ────────────────────────────────────────── var scene = EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single); // ── NetworkManager ─────────────────────────────────── var nmGO = new GameObject("NetworkManager"); var nm = nmGO.AddComponent(); var transport = nmGO.AddComponent(); nm.NetworkConfig = new NetworkConfig { NetworkTransport = transport }; // ── Network Prefabs 등록 ────────────────────────────── var playerPrefabAsset = AssetDatabase.LoadAssetAtPath("Assets/_Game/Prefabs/Player/Prefab_Player_Default.prefab"); if (playerPrefabAsset != null) AddNetworkPrefab(nm, playerPrefabAsset); else Debug.LogWarning("[LobbySceneBuilder] Player prefab not found at expected path."); // ── LobbyManager ───────────────────────────────────── var lmGO = new GameObject("LobbyManager"); lmGO.AddComponent(); lmGO.AddComponent(); // ── Canvas ─────────────────────────────────────────── var canvasGO = new GameObject("Canvas"); var canvas = canvasGO.AddComponent(); canvas.renderMode = RenderMode.ScreenSpaceOverlay; canvasGO.AddComponent().uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize; canvasGO.AddComponent(); // EventSystem — New Input System 사용 중이므로 InputSystemUIInputModule 사용 var esGO = new GameObject("EventSystem"); esGO.AddComponent(); esGO.AddComponent(); // ── ConnectPanel ────────────────────────────────────── var connectPanel = CreatePanel(canvasGO.transform, "ConnectPanel"); var connectRect = connectPanel.GetComponent(); connectRect.anchorMin = Vector2.zero; connectRect.anchorMax = Vector2.one; connectRect.offsetMin = Vector2.zero; connectRect.offsetMax = Vector2.zero; var vLayout = connectPanel.AddComponent(); vLayout.childAlignment = TextAnchor.MiddleCenter; vLayout.spacing = 12; vLayout.childForceExpandWidth = false; vLayout.childForceExpandHeight = false; connectPanel.AddComponent(); CreateLabel(connectPanel.transform, "TitleLabel", "Colosseum Lobby", 36, UIFontRole.Emphasis); var ipInput = CreateInputField(connectPanel.transform, "IpInput", "Host IP (127.0.0.1)", 300, 50); var portInput = CreateInputField(connectPanel.transform, "PortInput", "Port (7777)", 300, 50); var hostBtn = CreateButton(connectPanel.transform, "HostButton", "Host", 200, 50); var joinBtn = CreateButton(connectPanel.transform, "JoinButton", "Join", 200, 50); var statusText = CreateLabel(connectPanel.transform, "StatusText", "", 18, UIFontRole.Body); statusText.color = Color.yellow; // ── LobbyPanel ──────────────────────────────────────── var lobbyPanel = CreatePanel(canvasGO.transform, "LobbyPanel"); var lobbyRect = lobbyPanel.GetComponent(); lobbyRect.anchorMin = Vector2.zero; lobbyRect.anchorMax = Vector2.one; lobbyRect.offsetMin = Vector2.zero; lobbyRect.offsetMax = Vector2.zero; lobbyPanel.SetActive(false); var vLayout2 = lobbyPanel.AddComponent(); vLayout2.childAlignment = TextAnchor.MiddleCenter; vLayout2.spacing = 12; vLayout2.childForceExpandWidth = false; vLayout2.childForceExpandHeight = false; CreateLabel(lobbyPanel.transform, "LobbyTitle", "Waiting Room", 32, UIFontRole.Emphasis); // PlayerList: ScrollView 역할을 하는 VerticalLayout 컨테이너 var playerListGO = new GameObject("PlayerList"); playerListGO.transform.SetParent(lobbyPanel.transform, false); var plRect = playerListGO.AddComponent(); plRect.sizeDelta = new Vector2(400, 200); var plLayout = playerListGO.AddComponent(); plLayout.childAlignment = TextAnchor.UpperCenter; plLayout.spacing = 8; plLayout.childForceExpandWidth = true; plLayout.childForceExpandHeight = false; playerListGO.AddComponent().verticalFit = ContentSizeFitter.FitMode.PreferredSize; var readyBtn = CreateButton(lobbyPanel.transform, "ReadyButton", "준비", 200, 50); var startBtn = CreateButton(lobbyPanel.transform, "StartButton", "게임 시작", 200, 50); var discBtn = CreateButton(lobbyPanel.transform, "DisconnectButton", "나가기", 200, 50); // ── PlayerSlot 프리팹 ───────────────────────────────── var slotGO = new GameObject("PlayerSlot"); var slotRect = slotGO.AddComponent(); slotRect.sizeDelta = new Vector2(380, 40); var bg = slotGO.AddComponent(); bg.color = new Color(0.2f, 0.2f, 0.2f, 0.8f); var slotLabel = new GameObject("Label"); slotLabel.transform.SetParent(slotGO.transform, false); var slotLabelRect = slotLabel.AddComponent(); slotLabelRect.anchorMin = Vector2.zero; slotLabelRect.anchorMax = Vector2.one; slotLabelRect.offsetMin = new Vector2(8, 0); slotLabelRect.offsetMax = new Vector2(-8, 0); var slotTmp = slotLabel.AddComponent(); slotTmp.text = "Player"; slotTmp.fontSize = 20; slotTmp.alignment = TextAlignmentOptions.MidlineLeft; UIFontSetupTool.ApplyRole(slotTmp, UIFontRole.Body); System.IO.Directory.CreateDirectory(Application.dataPath + "/_Game/Prefabs/UI"); var slotPrefab = PrefabUtility.SaveAsPrefabAsset(slotGO, "Assets/_Game/Prefabs/UI/UI_PlayerSlot.prefab"); Object.DestroyImmediate(slotGO); // ── LobbyUI 연결 ────────────────────────────────────── var uiGO = new GameObject("UIController"); var lobbyUI = uiGO.AddComponent(); SetPrivateField(lobbyUI, "connectPanel", connectPanel); SetPrivateField(lobbyUI, "ipInput", ipInput.GetComponent()); SetPrivateField(lobbyUI, "portInput", portInput.GetComponent()); SetPrivateField(lobbyUI, "hostButton", hostBtn.GetComponent