| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604 |
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEngine.UIElements;
- using UnityEngine.InputSystem;
- public class GameUI : MonoBehaviour
- {
- [Header("UI Documents")]
- public UIDocument mainUIDocument;
- private VisualElement root;
- private Label woodLabel;
- private Label stoneLabel;
- private Label foodLabel;
- private Label timeSpeedLabel;
- private Button pauseButton;
- private Button speed1xButton;
- private Button speed2xButton;
- private Button speed10xButton;
- // Villager Panel
- private VisualElement villagerPanel;
- private Label villagerInfoLabel;
- private VisualElement jobButtonsContainer;
- private List<Button> jobButtons = new List<Button>();
- private Villager currentSelectedVillager; // Store reference to avoid deselection issues
- // Selected Object Panel
- private VisualElement selectionPanel;
- private Label selectionInfoLabel;
- void Start()
- {
- StartCoroutine(InitializeWhenReady());
- }
- System.Collections.IEnumerator InitializeWhenReady()
- {
- // Wait for GameManager to be initialized
- while (GameManager.Instance == null)
- {
- yield return null;
- }
- Debug.Log("GameManager found, initializing UI...");
- InitializeUI();
- SubscribeToEvents();
- // Update initial UI state after a short delay to ensure everything is ready
- yield return StartCoroutine(DelayedUIUpdate());
- }
- System.Collections.IEnumerator DelayedUIUpdate()
- {
- // Wait a few frames to ensure everything is initialized
- yield return new WaitForEndOfFrame();
- yield return new WaitForEndOfFrame();
- Debug.Log("Performing delayed UI update...");
- UpdateAllUI();
- // Force update resource displays with current values
- if (GameManager.Instance?.resourceManager != null)
- {
- var resources = GameManager.Instance.resourceManager.GetAllResources();
- Debug.Log($"Current resources: Wood={resources.GetValueOrDefault(ResourceType.Wood, 0)}, Stone={resources.GetValueOrDefault(ResourceType.Stone, 0)}, Food={resources.GetValueOrDefault(ResourceType.Food, 0)}");
- // Force manual UI updates
- foreach (var kvp in resources)
- {
- UpdateResourceDisplay(kvp.Key, kvp.Value);
- }
- }
- }
- void InitializeUI()
- {
- if (mainUIDocument == null)
- {
- mainUIDocument = GetComponent<UIDocument>();
- }
- if (mainUIDocument == null)
- {
- Debug.LogError("UI Document is required for GameUI! Please assign it in the inspector.");
- return;
- }
- Debug.Log($"UI Document found: {mainUIDocument.name}");
- Debug.Log($"UI Document's visual tree asset: {(mainUIDocument.visualTreeAsset != null ? mainUIDocument.visualTreeAsset.name : "NULL")}");
- if (mainUIDocument.visualTreeAsset == null)
- {
- Debug.LogWarning("UIDocument has no Visual Tree Asset assigned. Trying to auto-load...");
- // Try to load the UXML file from Resources folder
- VisualTreeAsset uxml = Resources.Load<VisualTreeAsset>("GameUI");
- if (uxml == null)
- {
- // Try alternative paths
- uxml = Resources.Load<VisualTreeAsset>("UI/GameUI");
- }
- if (uxml == null)
- {
- Debug.Log("Trying to load with .uxml extension...");
- // Some versions need explicit extension
- uxml = Resources.Load<VisualTreeAsset>("GameUI.uxml");
- }
- if (uxml != null)
- {
- mainUIDocument.visualTreeAsset = uxml;
- Debug.Log($"Auto-loaded UXML asset: {uxml.name}");
- }
- else
- {
- Debug.LogError("Could not auto-load GameUI.uxml! Please assign it manually or move it to Resources folder.");
- AttemptAutoFixUIDocument();
- return;
- }
- }
- root = mainUIDocument.rootVisualElement;
- Debug.Log($"Root element found: {root != null}, children count: {root?.childCount ?? 0}");
- if (root != null && root.childCount == 0)
- {
- Debug.LogError($"Root element has no children! The UXML file '{mainUIDocument.visualTreeAsset.name}' may be empty or not loading properly.");
- return;
- }
- // Get resource labels
- woodLabel = root.Q<Label>("wood-amount");
- stoneLabel = root.Q<Label>("stone-amount");
- foodLabel = root.Q<Label>("food-amount");
- Debug.Log($"Resource UI found - Wood: {woodLabel != null}, Stone: {stoneLabel != null}, Food: {foodLabel != null}");
- // Get time controls
- timeSpeedLabel = root.Q<Label>("time-speed");
- pauseButton = root.Q<Button>("pause-button");
- speed1xButton = root.Q<Button>("speed-1x");
- speed2xButton = root.Q<Button>("speed-2x");
- speed10xButton = root.Q<Button>("speed-10x");
- Debug.Log($"Time UI found - Speed: {timeSpeedLabel != null}, Pause: {pauseButton != null}, 1x: {speed1xButton != null}, 2x: {speed2xButton != null}, 10x: {speed10xButton != null}");
- // Get villager panel
- villagerPanel = root.Q<VisualElement>("villager-panel");
- villagerInfoLabel = root.Q<Label>("villager-info");
- jobButtonsContainer = root.Q<VisualElement>("job-buttons");
- Debug.Log($"Villager UI found - Panel: {villagerPanel != null}, Info: {villagerInfoLabel != null}, Jobs: {jobButtonsContainer != null}");
- // Get selection panel
- selectionPanel = root.Q<VisualElement>("selection-panel");
- selectionInfoLabel = root.Q<Label>("selection-info");
- Debug.Log($"Selection UI found - Panel: {selectionPanel != null}, Info: {selectionInfoLabel != null}");
- // Set up button callbacks
- SetupButtons();
- // Create job buttons
- CreateJobButtons();
- // Debug: List all found UI elements
- Debug.Log($"UI Initialization Summary:");
- Debug.Log($" Resource Labels - Wood: {woodLabel != null}, Stone: {stoneLabel != null}, Food: {foodLabel != null}");
- Debug.Log($" Time Controls - Speed Label: {timeSpeedLabel != null}, Buttons: {pauseButton != null}");
- Debug.Log($" Villager Panel - Panel: {villagerPanel != null}, Info: {villagerInfoLabel != null}");
- Debug.Log($" Selection Panel - Panel: {selectionPanel != null}, Info: {selectionInfoLabel != null}");
- // If no elements found, try to auto-fix by loading the UXML file
- if (woodLabel == null && stoneLabel == null && foodLabel == null)
- {
- AttemptAutoFixUIDocument();
- }
- }
- void AttemptAutoFixUIDocument()
- {
- Debug.LogError("=== UI SETUP ISSUE DETECTED ===");
- Debug.LogError("The UIDocument has no Visual Tree Asset assigned or the UXML file is empty.");
- Debug.LogError("To fix this:");
- Debug.LogError("1. Select the GameManager GameObject in the scene");
- Debug.LogError("2. Look at the UIDocument component in the inspector");
- Debug.LogError("3. Assign the GameUI.uxml file to the 'Visual Tree Asset' field");
- Debug.LogError("4. The GameUI.uxml file should be located at Assets/UI/GameUI.uxml");
- Debug.LogError("================================");
- }
- void SetupButtons()
- {
- // Time control buttons
- if (pauseButton != null)
- {
- pauseButton.RegisterCallback<ClickEvent>(evt =>
- {
- if (GameManager.Instance != null)
- {
- GameManager.Instance.TogglePause();
- Debug.Log("Pause button clicked");
- }
- });
- }
- if (speed1xButton != null)
- {
- speed1xButton.RegisterCallback<ClickEvent>(evt =>
- {
- if (GameManager.Instance?.timeManager != null)
- {
- GameManager.Instance.timeManager.SetSpeed(0);
- Debug.Log("1x speed button clicked");
- }
- });
- }
- if (speed2xButton != null)
- {
- speed2xButton.RegisterCallback<ClickEvent>(evt =>
- {
- if (GameManager.Instance?.timeManager != null)
- {
- GameManager.Instance.timeManager.SetSpeed(1);
- Debug.Log("2x speed button clicked");
- }
- });
- }
- if (speed10xButton != null)
- {
- speed10xButton.RegisterCallback<ClickEvent>(evt =>
- {
- if (GameManager.Instance?.timeManager != null)
- {
- GameManager.Instance.timeManager.SetSpeed(2);
- Debug.Log("10x speed button clicked");
- }
- });
- }
- }
- void CreateJobButtons()
- {
- if (jobButtonsContainer == null)
- {
- Debug.LogWarning("Job buttons container not found!");
- return;
- }
- // Clear existing buttons
- jobButtonsContainer.Clear();
- jobButtons.Clear();
- // Create job buttons (skip None job type)
- foreach (JobType job in System.Enum.GetValues(typeof(JobType)))
- {
- if (job == JobType.None) continue; // Skip "None" job
- Button jobButton = new Button();
- jobButton.text = GetJobDisplayName(job);
- jobButton.AddToClassList("job-button");
- jobButton.RegisterCallback<ClickEvent>(evt => AssignJobToSelectedVillager(job));
- // Initially disable all job buttons
- jobButton.SetEnabled(false);
- jobButtonsContainer.Add(jobButton);
- jobButtons.Add(jobButton);
- }
- Debug.Log($"Created {jobButtons.Count} job buttons (initially disabled)");
- }
- string GetJobDisplayName(JobType job)
- {
- return job switch
- {
- JobType.Woodcutter => "Woodcutter",
- JobType.Stonecutter => "Stonecutter",
- JobType.Farmer => "Farmer",
- JobType.Builder => "Builder",
- _ => job.ToString()
- };
- }
- void AssignJobToSelectedVillager(JobType job)
- {
- // Use stored reference instead of real-time selection to avoid deselection issues
- if (currentSelectedVillager == null)
- {
- Debug.Log("No villager stored for job assignment - this shouldn't happen if buttons are disabled properly");
- return;
- }
- if (GameManager.Instance?.villagerManager == null)
- {
- Debug.LogWarning("VillagerManager not found!");
- return;
- }
- Debug.Log($"Assigning job {job} to stored villager: {currentSelectedVillager.name}");
- // Find the closest available workplace for this job
- GameObject workplace = GameManager.Instance.villagerManager.FindWorkplaceForJob(job, currentSelectedVillager.transform.position);
- if (workplace != null)
- {
- // Assign villager to specific workplace
- GameManager.Instance.villagerManager.AssignVillagerToSpecificWorkplace(currentSelectedVillager, job, workplace);
- Debug.Log($"Assigned {currentSelectedVillager.name} to {job} at {workplace.name}");
- }
- else
- {
- // Fallback to general job assignment if no specific workplace found
- GameManager.Instance.villagerManager.AssignVillagerToJob(currentSelectedVillager, job);
- Debug.Log($"Assigned {currentSelectedVillager.name} to {job} (no specific workplace found)");
- }
- // Update the villager panel to show new job
- UpdateVillagerPanel(currentSelectedVillager);
- }
- void SubscribeToEvents()
- {
- // Subscribe to resource changes
- ResourceManager.OnResourceChanged += UpdateResourceDisplay;
- // Subscribe to time changes
- TimeManager.OnTimeSpeedChanged += UpdateTimeDisplay;
- TimeManager.OnPauseStateChanged += UpdatePauseDisplay;
- // Subscribe to villager selection
- Villager.OnVillagerSelected += UpdateVillagerPanel;
- }
- void OnDestroy()
- {
- // Unsubscribe from events
- ResourceManager.OnResourceChanged -= UpdateResourceDisplay;
- TimeManager.OnTimeSpeedChanged -= UpdateTimeDisplay;
- TimeManager.OnPauseStateChanged -= UpdatePauseDisplay;
- Villager.OnVillagerSelected -= UpdateVillagerPanel;
- }
- void UpdateAllUI()
- {
- // Update resource displays
- if (GameManager.Instance?.resourceManager != null)
- {
- var resources = GameManager.Instance.resourceManager.GetAllResources();
- foreach (var kvp in resources)
- {
- UpdateResourceDisplay(kvp.Key, kvp.Value);
- }
- }
- // Update time display
- if (GameManager.Instance?.timeManager != null)
- {
- UpdateTimeDisplay(GameManager.Instance.timeManager.CurrentTimeScale);
- UpdatePauseDisplay(GameManager.Instance.timeManager.IsPaused);
- }
- // Update selection
- UpdateSelectionPanel();
- }
- void UpdateResourceDisplay(ResourceType type, int amount)
- {
- Label targetLabel = null;
- string elementName = "";
- switch (type)
- {
- case ResourceType.Wood:
- targetLabel = woodLabel;
- elementName = "wood-amount";
- break;
- case ResourceType.Stone:
- targetLabel = stoneLabel;
- elementName = "stone-amount";
- break;
- case ResourceType.Food:
- targetLabel = foodLabel;
- elementName = "food-amount";
- break;
- }
- if (targetLabel != null)
- {
- targetLabel.text = amount.ToString();
- Debug.Log($"Updated {type} to {amount} successfully");
- }
- else
- {
- Debug.LogWarning($"Could not find UI label for {type} (looking for '{elementName}')");
- // Try to re-find the element
- if (root != null)
- {
- targetLabel = root.Q<Label>(elementName);
- if (targetLabel != null)
- {
- targetLabel.text = amount.ToString();
- Debug.Log($"Re-found and updated {type} to {amount}");
- // Update the cached reference
- switch (type)
- {
- case ResourceType.Wood: woodLabel = targetLabel; break;
- case ResourceType.Stone: stoneLabel = targetLabel; break;
- case ResourceType.Food: foodLabel = targetLabel; break;
- }
- }
- else
- {
- Debug.LogError($"Element '{elementName}' not found in UXML! Check that the UXML file contains an element with name='{elementName}'");
- }
- }
- }
- }
- void UpdateTimeDisplay(float timeScale)
- {
- if (timeSpeedLabel != null)
- {
- if (timeScale == 0f)
- {
- timeSpeedLabel.text = "Paused";
- }
- else if (timeScale == 1f)
- {
- timeSpeedLabel.text = "1x";
- }
- else if (timeScale == 2f)
- {
- timeSpeedLabel.text = "2x";
- }
- else if (timeScale == 10f)
- {
- timeSpeedLabel.text = "10x";
- }
- else
- {
- timeSpeedLabel.text = $"{timeScale}x";
- }
- Debug.Log($"Updated time speed to {timeSpeedLabel.text}");
- }
- else
- {
- Debug.LogWarning("Time speed label not found!");
- }
- }
- void UpdatePauseDisplay(bool isPaused)
- {
- if (pauseButton != null)
- {
- pauseButton.text = isPaused ? "Resume" : "Pause";
- Debug.Log($"Updated pause button to: {pauseButton.text}");
- }
- if (timeSpeedLabel != null && isPaused)
- {
- timeSpeedLabel.text = "Paused";
- }
- }
- public void UpdateVillagerPanel(Villager villager)
- {
- Debug.Log($"UpdateVillagerPanel called for: {(villager != null ? villager.name : "null")}");
- // Store the villager reference for job assignment
- currentSelectedVillager = villager;
- Debug.Log($"Stored villager reference: {(currentSelectedVillager != null ? currentSelectedVillager.name : "null")}");
- if (villagerInfoLabel == null)
- {
- Debug.LogWarning("villagerInfoLabel is null - cannot show villager info");
- return;
- }
- // Update job button states
- UpdateJobButtonStates(villager);
- if (villager == null)
- {
- villagerInfoLabel.text = "No villager selected";
- Debug.Log("Updated villager panel: No villager selected");
- }
- else
- {
- string jobText = villager.currentJob == JobType.None ? "Unemployed" : GetJobDisplayName(villager.currentJob);
- string info = $"Name: {villager.name}\n" +
- $"Job: {jobText}\n" +
- $"Experience: {villager.experience.GetExperienceForJob(villager.currentJob):F1}\n" +
- $"State: {villager.state}";
- villagerInfoLabel.text = info;
- Debug.Log($"Updated villager panel with info: {info}");
- }
- }
- void UpdateJobButtonStates(Villager selectedVillager)
- {
- bool hasSelection = selectedVillager != null;
- // Enable/disable all job buttons based on villager selection
- foreach (var button in jobButtons)
- {
- button.SetEnabled(hasSelection);
- // Optional: Change button appearance based on villager's current job
- if (hasSelection)
- {
- string buttonJobName = button.text;
- string currentJobName = GetJobDisplayName(selectedVillager.currentJob);
- if (buttonJobName == currentJobName)
- {
- button.AddToClassList("current-job"); // You can style this in USS
- }
- else
- {
- button.RemoveFromClassList("current-job");
- }
- }
- }
- Debug.Log($"Job buttons {(hasSelection ? "enabled" : "disabled")} - {jobButtons.Count} buttons updated");
- }
- // Public method to manually refresh all UI elements
- public void ManualUIRefresh()
- {
- Debug.Log("Manual UI refresh requested");
- // Re-find all UI elements
- if (root != null)
- {
- woodLabel = root.Q<Label>("wood-amount");
- stoneLabel = root.Q<Label>("stone-amount");
- foodLabel = root.Q<Label>("food-amount");
- villagerInfoLabel = root.Q<Label>("villager-info");
- selectionInfoLabel = root.Q<Label>("selection-info");
- Debug.Log($"Re-found UI elements - Wood: {woodLabel != null}, Stone: {stoneLabel != null}, Food: {foodLabel != null}, VillagerInfo: {villagerInfoLabel != null}");
- // Force update all displays
- UpdateAllUI();
- }
- }
- void Update()
- {
- // Check for debug key to manually refresh UI
- if (Keyboard.current != null && Keyboard.current.f5Key.wasPressedThisFrame)
- {
- Debug.Log("F5 pressed - Manual UI refresh");
- ManualUIRefresh();
- }
- }
- void UpdateSelectionPanel()
- {
- if (selectionInfoLabel == null) return;
- var selectedObject = GameManager.Instance?.selectionManager?.SelectedObject;
- var selectedVillager = GameManager.Instance?.selectionManager?.SelectedVillager;
- if (selectedObject == null && selectedVillager == null)
- {
- selectionInfoLabel.text = "Nothing selected";
- return;
- }
- string info = "";
- if (selectedVillager != null)
- {
- info = $"Selected: {selectedVillager.name}";
- }
- else if (selectedObject != null)
- {
- // Add specific info based on object type
- Building building = selectedObject.GetComponent<Building>();
- if (building != null)
- {
- info = building.GetBuildingInfo();
- }
- else
- {
- ResourceNode node = selectedObject.GetComponent<ResourceNode>();
- if (node != null)
- {
- info = node.GetNodeInfo();
- }
- else
- {
- info = "Selected: " + selectedObject.name;
- }
- }
- }
- selectionInfoLabel.text = info;
- }
- }
|