diff --git a/unity-client/Assets/Editor/CreateSimulatorScene.cs b/unity-client/Assets/Editor/CreateSimulatorScene.cs index dd1469f..eebdab2 100644 --- a/unity-client/Assets/Editor/CreateSimulatorScene.cs +++ b/unity-client/Assets/Editor/CreateSimulatorScene.cs @@ -14,11 +14,13 @@ public static class CreateSimulatorScene { var scene = EditorSceneManager.NewScene(NewSceneSetup.DefaultGameObjects, NewSceneMode.Single); + // ── Services ────────────────────────────────────────────────────────── var services = new GameObject("[Services]"); services.AddComponent(); + // ── Canvas ──────────────────────────────────────────────────────────── var canvasGo = new GameObject("Canvas"); - var canvas = canvasGo.AddComponent(); + var canvas = canvasGo.AddComponent(); canvas.renderMode = RenderMode.ScreenSpaceOverlay; var scaler = canvasGo.AddComponent(); scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize; @@ -32,56 +34,166 @@ public static class CreateSimulatorScene es.AddComponent(); } + // ── Background ──────────────────────────────────────────────────────── CreatePanel(canvasGo.transform, "Background", new Color(0.08f, 0.08f, 0.12f), stretch: true); - // Header - var header = CreatePanel(canvasGo.transform, "Header", new Color(0.12f, 0.12f, 0.18f)); + // ── Header (Top Bar) ────────────────────────────────────────────────── + var header = CreatePanel(canvasGo.transform, "Header", new Color(0.12f, 0.12f, 0.18f, 0.95f)); SetAnchors(header.GetComponent(), new Vector2(0f, 0.93f), new Vector2(1f, 1f)); + var backBtn = CreateTMPButton(header.transform, "BackButton", "< Back", new Color(0.2f, 0.2f, 0.3f)); SetAnchors(backBtn.GetComponent(), new Vector2(0.01f, 0.1f), new Vector2(0.08f, 0.9f)); - var title = CreateTMPText(header.transform, "TitleText", "Simulator", 28, FontStyles.Bold, TextAlignmentOptions.Center); - SetAnchors(title.GetComponent(), new Vector2(0.3f, 0.1f), new Vector2(0.7f, 0.9f)); - // Config Panel - var configPanel = CreatePanel(canvasGo.transform, "ConfigPanel", new Color(0.1f, 0.1f, 0.16f)); - SetAnchors(configPanel.GetComponent(), new Vector2(0.05f, 0.35f), new Vector2(0.5f, 0.93f)); + var titleTxt = CreateTMPText(header.transform, "TitleText", "Simulator", 28, FontStyles.Bold, TextAlignmentOptions.Center); + SetAnchors(titleTxt.GetComponent(), new Vector2(0.3f, 0.1f), new Vector2(0.7f, 0.9f)); + + var startSimBtn = CreateTMPButton(header.transform, "StartSimButton", "Start Simulation", new Color(0.2f, 0.55f, 0.2f)); + SetAnchors(startSimBtn.GetComponent(), new Vector2(0.82f, 0.1f), new Vector2(0.99f, 0.9f)); + + // ── Config Panel (left) ─────────────────────────────────────────────── + var configPanel = CreatePanel(canvasGo.transform, "ConfigPanel", new Color(0.1f, 0.1f, 0.16f, 0.97f)); + SetAnchors(configPanel.GetComponent(), new Vector2(0.01f, 0.3f), new Vector2(0.49f, 0.93f)); var cfgVlg = configPanel.AddComponent(); - cfgVlg.padding = new RectOffset(16, 16, 16, 16); cfgVlg.spacing = 10; - cfgVlg.childForceExpandWidth = true; cfgVlg.childForceExpandHeight = false; + cfgVlg.padding = new RectOffset(16, 16, 16, 16); + cfgVlg.spacing = 10; + cfgVlg.childForceExpandWidth = true; + cfgVlg.childForceExpandHeight = false; CreateTMPText(configPanel.transform, "ConfigTitle", "Simulation Config", 20, FontStyles.Bold, TextAlignmentOptions.Center); - // Deck selector - var deckLabel = CreateTMPText(configPanel.transform, "DeckLabel", "Deck:", 16, FontStyles.Normal, TextAlignmentOptions.Left); - var deckInput = CreateTMPInputField(configPanel.transform, "DeckInput", "Deck ID or name..."); + // Deck dropdowns + var deckDropdown0 = CreateTMPDropdown(configPanel.transform, "DeckDropdown0", new[] { "-- Select Deck --" }); + var deckDropdown1 = CreateTMPDropdown(configPanel.transform, "DeckDropdown1", new[] { "-- Select Deck --" }); + var deckDropdown2 = CreateTMPDropdown(configPanel.transform, "DeckDropdown2", new[] { "-- Select Deck --" }); + var deckDropdown3 = CreateTMPDropdown(configPanel.transform, "DeckDropdown3", new[] { "-- Select Deck --" }); - // Num games - var gamesLabel = CreateTMPText(configPanel.transform, "GamesLabel", "Games:", 16, FontStyles.Normal, TextAlignmentOptions.Left); - var gamesInput = CreateTMPInputField(configPanel.transform, "GamesInput", "100"); + // Num players slider + var numPlayersLabel = CreateTMPText(configPanel.transform, "NumPlayersLabel", "Players: 2", 16, FontStyles.Normal, TextAlignmentOptions.Left); + var numPlayersSlider = CreateSlider(configPanel.transform, "NumPlayersSlider"); - // Start/Stop buttons - var startBtn = CreateTMPButton(configPanel.transform, "StartButton", "Start Simulation", new Color(0.2f, 0.55f, 0.2f)); - var stopBtn = CreateTMPButton(configPanel.transform, "StopButton", "Stop", new Color(0.55f, 0.2f, 0.2f)); + // Num games input + CreateTMPText(configPanel.transform, "NumGamesLabel", "Number of Games:", 16, FontStyles.Normal, TextAlignmentOptions.Left); + var numGamesInput = CreateTMPInputField(configPanel.transform, "NumGamesInput", "100"); - // Results Panel - var resultsPanel = CreatePanel(canvasGo.transform, "ResultsPanel", new Color(0.1f, 0.1f, 0.16f)); - SetAnchors(resultsPanel.GetComponent(), new Vector2(0.52f, 0.35f), new Vector2(0.95f, 0.93f)); + // Threads input + CreateTMPText(configPanel.transform, "ThreadsLabel", "Threads:", 16, FontStyles.Normal, TextAlignmentOptions.Left); + var threadsInput = CreateTMPInputField(configPanel.transform, "ThreadsInput", "4"); - var resultsTitle = CreateTMPText(resultsPanel.transform, "ResultsTitle", "Results", 20, FontStyles.Bold, TextAlignmentOptions.Center); - SetAnchors(resultsTitle.GetComponent(), new Vector2(0f, 0.90f), new Vector2(1f, 1f)); + // AI Profile dropdown + CreateTMPText(configPanel.transform, "AiProfileLabel", "AI Profile:", 16, FontStyles.Normal, TextAlignmentOptions.Left); + var aiProfileDropdown = CreateTMPDropdown(configPanel.transform, "AiProfileDropdown", new[] { "Default" }); - var statusText = CreateTMPText(resultsPanel.transform, "StatusText", "Ready", 16, FontStyles.Normal, TextAlignmentOptions.TopLeft); - SetAnchors(statusText.GetComponent(), new Vector2(0.03f, 0.03f), new Vector2(0.97f, 0.90f)); + // ── Status Panel (center, hidden initially) ─────────────────────────── + var statusPanel = CreatePanel(canvasGo.transform, "StatusPanel", new Color(0.09f, 0.09f, 0.14f, 0.97f)); + SetAnchors(statusPanel.GetComponent(), new Vector2(0.01f, 0.06f), new Vector2(0.49f, 0.29f)); + statusPanel.SetActive(false); + var stVlg = statusPanel.AddComponent(); + stVlg.padding = new RectOffset(12, 12, 10, 10); + stVlg.spacing = 6; + stVlg.childForceExpandWidth = true; + stVlg.childForceExpandHeight = false; - // Progress bar - var progressBg = CreatePanel(canvasGo.transform, "ProgressBar", new Color(0.2f, 0.2f, 0.25f)); - SetAnchors(progressBg.GetComponent(), new Vector2(0.05f, 0.28f), new Vector2(0.95f, 0.33f)); - var progressFill = CreatePanel(progressBg.transform, "ProgressFill", new Color(0.2f, 0.6f, 0.3f)); - SetAnchors(progressFill.GetComponent(), new Vector2(0f, 0f), new Vector2(0f, 1f)); - var progressText = CreateTMPText(progressBg.transform, "ProgressText", "0%", 14, FontStyles.Normal, TextAlignmentOptions.Center); - SetAnchors(progressText.GetComponent(), new Vector2(0f, 0f), new Vector2(1f, 1f)); + var statusText = CreateTMPText(statusPanel.transform, "StatusText", "Ready", 16, FontStyles.Normal, TextAlignmentOptions.TopLeft); + var progressBar = CreateSlider(statusPanel.transform, "ProgressBar"); + var progressText = CreateTMPText(statusPanel.transform, "ProgressText", "0%", 14, FontStyles.Normal, TextAlignmentOptions.Center); + var elapsedText = CreateTMPText(statusPanel.transform, "ElapsedText", "Elapsed: 0s", 14, FontStyles.Normal, TextAlignmentOptions.Left); + var simsPerSecText = CreateTMPText(statusPanel.transform, "SimsPerSecText", "0 sims/s", 14, FontStyles.Normal, TextAlignmentOptions.Left); - // -- Save -- + // ── Results Panel (right, hidden initially) ─────────────────────────── + var resultsPanel = CreatePanel(canvasGo.transform, "ResultsPanel", new Color(0.1f, 0.1f, 0.16f, 0.97f)); + SetAnchors(resultsPanel.GetComponent(), new Vector2(0.51f, 0.06f), new Vector2(0.99f, 0.93f)); + resultsPanel.SetActive(false); + + CreateTMPText(resultsPanel.transform, "ResultsTitle", "Results", 22, FontStyles.Bold, TextAlignmentOptions.Center); + var winnerText = CreateTMPText(resultsPanel.transform, "WinnerText", "Winner: —", 18, FontStyles.Bold, TextAlignmentOptions.Center); + SetAnchors(winnerText.GetComponent(), new Vector2(0f, 0.88f), new Vector2(1f, 0.95f)); + + // Results scroll view + var resultsScroll = new GameObject("ResultsScroll"); + resultsScroll.transform.SetParent(resultsPanel.transform, false); + SetAnchors(resultsScroll.GetComponent(), new Vector2(0f, 0.15f), new Vector2(1f, 0.88f)); + ScrollRect resSr; + var resultsContent = CreateScrollContent(resultsScroll, out resSr); + + var historyBtn = CreateTMPButton(resultsPanel.transform, "HistoryButton", "View History", new Color(0.2f, 0.4f, 0.7f)); + SetAnchors(historyBtn.GetComponent(), new Vector2(0.2f, 0.03f), new Vector2(0.8f, 0.13f)); + + // ── Error Panel (hidden initially) ──────────────────────────────────── + var errorPanel = CreatePanel(canvasGo.transform, "ErrorPanel", new Color(0.15f, 0.05f, 0.05f, 0.97f)); + SetAnchors(errorPanel.GetComponent(), new Vector2(0.25f, 0.35f), new Vector2(0.75f, 0.65f)); + errorPanel.SetActive(false); + + CreateTMPText(errorPanel.transform, "ErrorTitle", "Error", 22, FontStyles.Bold, TextAlignmentOptions.Center); + var errorText = CreateTMPText(errorPanel.transform, "ErrorText", "", 16, FontStyles.Normal, TextAlignmentOptions.TopLeft); + SetAnchors(errorText.GetComponent(), new Vector2(0.05f, 0.25f), new Vector2(0.95f, 0.85f)); + var retryBtn = CreateTMPButton(errorPanel.transform, "RetryButton", "Retry", new Color(0.55f, 0.2f, 0.2f)); + SetAnchors(retryBtn.GetComponent(), new Vector2(0.3f, 0.05f), new Vector2(0.7f, 0.22f)); + + // ── Result Row Prefab (disabled child object used as prefab) ────────── + var resultRowPrefab = new GameObject("ResultRowPrefab"); + resultRowPrefab.transform.SetParent(canvasGo.transform, false); + resultRowPrefab.SetActive(false); + var rowImg = resultRowPrefab.AddComponent(); + rowImg.color = new Color(0.15f, 0.15f, 0.2f, 0.9f); + var rowHlg = resultRowPrefab.AddComponent(); + rowHlg.padding = new RectOffset(8, 8, 4, 4); + rowHlg.spacing = 12; + rowHlg.childForceExpandWidth = false; + rowHlg.childForceExpandHeight = true; + var rowLe = resultRowPrefab.AddComponent(); + rowLe.minHeight = 40; + + string[] colNames = { "DeckName", "WinRate", "Wins", "Losses" }; + float[] colWidths = { 300f, 120f, 100f, 100f }; + for (int i = 0; i < colNames.Length; i++) + { + var cell = new GameObject(colNames[i]); + cell.transform.SetParent(resultRowPrefab.transform, false); + var cellTxt = cell.AddComponent(); + cellTxt.text = colNames[i]; + cellTxt.fontSize = 16; + cellTxt.color = Color.white; + cellTxt.alignment = TextAlignmentOptions.Left; + var cellLe = cell.AddComponent(); + cellLe.minWidth = colWidths[i]; + cellLe.preferredWidth = colWidths[i]; + cellLe.flexibleWidth = i == 0 ? 1f : 0f; + } + + // ── Wire SimulationController via reflection ─────────────────────────── + var controllerGo = new GameObject("SimulationController"); + controllerGo.transform.SetParent(canvasGo.transform, false); + var controller = controllerGo.AddComponent(); + + SetField(controller, "backButton", backBtn.GetComponent