| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683 |
- using UnityEngine;
- using UnityEngine.UIElements;
- using System.Collections.Generic;
- using System.Collections;
- public class MapLocationNameDisplay : MonoBehaviour, IClickBlocker
- {
- [Header("System Control")]
- public bool systemEnabled = false; // Disabled - moving to 3D world space approach
- [Header("UI References")]
- public UIDocument mapUIDocument;
- [Header("Display Settings")]
- public bool showSettlementNames = true;
- public bool showForestNames = true;
- public bool showLakeNames = true;
- public bool showPlainNames = true;
- public bool showMountainNames = true;
- public bool showRiverNames = true;
- [Header("Visual Settings")]
- public Color settlementNameColor = Color.white;
- public Color forestNameColor = Color.green;
- public Color lakeNameColor = Color.cyan;
- public Color plainNameColor = Color.yellow;
- public Color mountainNameColor = Color.gray;
- public Color riverNameColor = Color.blue;
- [Header("World Positioning")]
- public bool debugMode = true;
- public float updateFrequency = 0.33f; // Update positions 3 times per second for good performance
- private VisualElement mapContainer;
- private List<Label> nameLabels = new List<Label>();
- private List<Vector3> worldPositions = new List<Vector3>(); // Store world positions for each label
- private GeographicFeatureManager featureManager;
- private MapData mapData;
- private MapMaker2 mapMaker;
- private Camera mainCamera;
- private Coroutine positionUpdateCoroutine;
- private Vector3 lastCameraPosition;
- private float lastCameraSize;
- private void Start()
- {
- if (!systemEnabled)
- {
- if (debugMode) Debug.Log("MapLocationNameDisplay: System disabled, not initializing");
- return;
- }
- InitializeReferences();
- SetupUI();
- // Find the main camera
- mainCamera = Camera.main;
- if (mainCamera == null)
- {
- mainCamera = FindFirstObjectByType<Camera>();
- }
- // Initialize camera tracking
- if (mainCamera != null)
- {
- lastCameraPosition = mainCamera.transform.position;
- lastCameraSize = mainCamera.orthographicSize;
- }
- if (debugMode)
- {
- Debug.Log($"MapLocationNameDisplay: Started. MapData: {(mapData != null ? $"{mapData.Width}x{mapData.Height}" : "NULL")}");
- Debug.Log($"MapLocationNameDisplay: FeatureManager: {(featureManager != null ? "Found" : "NULL")}");
- Debug.Log($"MapLocationNameDisplay: MapContainer: {(mapContainer != null ? "Created" : "NULL")}");
- Debug.Log($"MapLocationNameDisplay: Camera: {(mainCamera != null ? "Found" : "NULL")}");
- }
- // Initial refresh of location names
- StartCoroutine(InitialRefreshDelayed());
- }
- private void InitializeReferences()
- {
- if (mapUIDocument == null)
- mapUIDocument = GetComponent<UIDocument>();
- featureManager = FindFirstObjectByType<GeographicFeatureManager>();
- mapMaker = FindFirstObjectByType<MapMaker2>();
- if (mapMaker != null)
- {
- mapData = mapMaker.GetMapData();
- }
- if (debugMode)
- {
- Debug.Log($"MapLocationNameDisplay.InitializeReferences:");
- Debug.Log($" - mapUIDocument: {(mapUIDocument != null ? "Found" : "NULL")}");
- Debug.Log($" - featureManager: {(featureManager != null ? $"Found ({featureManager.GeographicFeatures.Count} features)" : "NULL")}");
- Debug.Log($" - mapMaker: {(mapMaker != null ? "Found" : "NULL")}");
- Debug.Log($" - mapData: {(mapData != null ? $"Found ({mapData.Width}x{mapData.Height})" : "NULL")}");
- }
- }
- private void SetupUI()
- {
- if (mapUIDocument?.rootVisualElement != null)
- {
- // Load the CSS for proper layering
- var layerStyleSheet = Resources.Load<StyleSheet>("UI/MapLocationNamesLayer");
- if (layerStyleSheet != null)
- {
- mapUIDocument.rootVisualElement.styleSheets.Add(layerStyleSheet);
- if (debugMode) Debug.Log("MapLocationNameDisplay: Loaded MapLocationNamesLayer stylesheet");
- }
- else if (debugMode)
- {
- Debug.LogWarning("MapLocationNameDisplay: Could not load MapLocationNamesLayer stylesheet from Resources/UI/");
- }
- // Try to find existing map container
- mapContainer = mapUIDocument.rootVisualElement.Q<VisualElement>("map-container");
- if (mapContainer == null)
- {
- // Create map container if it doesn't exist
- mapContainer = new VisualElement();
- mapContainer.name = "map-container";
- mapContainer.style.position = Position.Absolute;
- mapContainer.style.width = Length.Percent(100);
- mapContainer.style.height = Length.Percent(100);
- mapContainer.style.left = 0;
- mapContainer.style.top = 0;
- mapContainer.pickingMode = PickingMode.Ignore; // Allow clicks to pass through
- // Ensure the container is visible and can contain children
- mapContainer.style.overflow = Overflow.Visible;
- mapContainer.style.visibility = Visibility.Visible;
- mapContainer.style.display = DisplayStyle.Flex;
- // Use CSS to control layering instead of insertion position
- mapContainer.AddToClassList("map-location-names-layer");
- // Add to the end of the hierarchy, but use CSS z-index to control layering
- mapUIDocument.rootVisualElement.Add(mapContainer);
- if (debugMode) Debug.Log("MapLocationNameDisplay: Created new map-container with click-through enabled");
- }
- else
- {
- // Ensure existing container also has proper picking mode and visibility
- mapContainer.pickingMode = PickingMode.Ignore;
- mapContainer.AddToClassList("map-location-names-layer");
- mapContainer.style.overflow = Overflow.Visible;
- mapContainer.style.visibility = Visibility.Visible;
- mapContainer.style.display = DisplayStyle.Flex;
- if (debugMode) Debug.Log($"MapLocationNameDisplay: Found existing map-container with {mapContainer.childCount} children, ensured click-through");
- }
- }
- else if (debugMode)
- {
- Debug.LogWarning("MapLocationNameDisplay: mapUIDocument or rootVisualElement is null");
- }
- }
- public void OnFeaturesGenerated()
- {
- // Wait a frame to ensure everything is set up
- StartCoroutine(RefreshNamesDelayed());
- }
- private System.Collections.IEnumerator InitialRefreshDelayed()
- {
- yield return null; // Wait one frame for setup
- yield return null; // Wait another frame to be sure
- if (debugMode) Debug.Log("MapLocationNameDisplay: Initial refresh triggered");
- RefreshLocationNames();
- }
- private System.Collections.IEnumerator RefreshNamesDelayed()
- {
- yield return null; // Wait one frame
- yield return null; // Wait another frame to be sure
- if (debugMode) Debug.Log("MapLocationNameDisplay: Delayed refresh triggered");
- RefreshLocationNames();
- }
- public void RefreshLocationNames()
- {
- if (!systemEnabled)
- {
- if (debugMode) Debug.Log("MapLocationNameDisplay: System disabled, skipping refresh");
- return;
- }
- ClearAllLabels();
- if (mapContainer == null || mapData == null)
- {
- if (debugMode) Debug.LogWarning($"MapLocationNameDisplay: Cannot refresh - mapContainer: {(mapContainer != null ? "OK" : "NULL")}, mapData: {(mapData != null ? "OK" : "NULL")}");
- return;
- }
- if (debugMode) Debug.Log($"MapLocationNameDisplay: Refreshing location names... Container children before: {mapContainer.childCount}");
- // Display settlement names
- if (showSettlementNames)
- {
- if (debugMode) Debug.Log("MapLocationNameDisplay: Attempting to display settlement names...");
- DisplaySettlementNames();
- }
- // Display geographic feature names
- if (featureManager != null)
- {
- if (debugMode) Debug.Log($"MapLocationNameDisplay: Found {featureManager.GeographicFeatures.Count} geographic features");
- var features = featureManager.GeographicFeatures;
- if (debugMode) Debug.Log($"MapLocationNameDisplay: Found {features.Count} geographic features");
- foreach (var feature in features)
- {
- if (ShouldDisplayFeature(feature))
- {
- CreateFeatureLabel(feature);
- }
- }
- }
- else if (debugMode)
- {
- Debug.LogWarning("MapLocationNameDisplay: FeatureManager is null");
- }
- if (debugMode) Debug.Log($"MapLocationNameDisplay: Created {nameLabels.Count} name labels total");
- // Debug final container state
- if (debugMode && mapContainer != null)
- {
- Debug.Log($"MapLocationNameDisplay: Final container state - Children: {mapContainer.childCount}, PickingMode: {mapContainer.pickingMode}, Parent: {(mapContainer.parent != null ? mapContainer.parent.name : "NULL")}");
- Debug.Log($"MapLocationNameDisplay: Container bounds: {mapContainer.localBound}, World bounds: {mapContainer.worldBound}");
- Debug.Log($"MapLocationNameDisplay: Container visible: {mapContainer.style.visibility}, Display: {mapContainer.style.display}, Overflow: {mapContainer.style.overflow}");
- Debug.Log($"MapLocationNameDisplay: Container size: width={mapContainer.style.width}, height={mapContainer.style.height}");
- Debug.Log($"MapLocationNameDisplay: Container position: left={mapContainer.style.left}, top={mapContainer.style.top}, position={mapContainer.style.position}");
- // Double-check that labels are actually in the container
- if (mapContainer.childCount != nameLabels.Count)
- {
- Debug.LogError($"MapLocationNameDisplay: MISMATCH! Container has {mapContainer.childCount} children but nameLabels has {nameLabels.Count} items!");
- // Try to re-add labels if they're missing
- for (int i = 0; i < nameLabels.Count; i++)
- {
- if (nameLabels[i].parent == null)
- {
- Debug.Log($"MapLocationNameDisplay: Re-adding orphaned label: {nameLabels[i].text}");
- mapContainer.Add(nameLabels[i]);
- }
- }
- Debug.Log($"MapLocationNameDisplay: After re-adding, container has {mapContainer.childCount} children");
- }
- else
- {
- Debug.Log($"MapLocationNameDisplay: SUCCESS! Container and nameLabels count match: {mapContainer.childCount}");
- // Check first few labels for debugging
- for (int i = 0; i < Mathf.Min(3, nameLabels.Count); i++)
- {
- var label = nameLabels[i];
- Debug.Log($"MapLocationNameDisplay: Label {i}: '{label.text}' - Visible: {label.style.visibility}, Display: {label.style.display}, Position: ({label.style.left.value.value:F1}, {label.style.top.value.value:F1}), PickingMode: {label.pickingMode}, Parent: {(label.parent != null ? label.parent.name : "NULL")}");
- }
- }
- }
- // Start position updates if we have labels and camera
- if (nameLabels.Count > 0 && mainCamera != null)
- {
- StartPositionUpdates();
- if (debugMode) Debug.Log("MapLocationNameDisplay: Started continuous position updates");
- }
- }
- private void OnDestroy()
- {
- StopPositionUpdates();
- }
- private void DisplaySettlementNames()
- {
- var settlements = mapData.GetAllSettlements();
- if (debugMode) Debug.Log($"MapLocationNameDisplay: Displaying {settlements.Count} settlement names");
- foreach (var settlement in settlements)
- {
- CreateSettlementLabel(settlement);
- }
- }
- private bool ShouldDisplayFeature(GeographicFeature feature)
- {
- switch (feature.type)
- {
- case GeographicFeatureType.Forest:
- return showForestNames;
- case GeographicFeatureType.Lake:
- return showLakeNames;
- case GeographicFeatureType.Plain:
- return showPlainNames;
- case GeographicFeatureType.Mountain:
- return showMountainNames;
- case GeographicFeatureType.River:
- return showRiverNames;
- default:
- return false;
- }
- }
- private void CreateSettlementLabel(Settlement settlement)
- {
- var label = new Label(settlement.name);
- label.AddToClassList("location-name-label");
- label.AddToClassList("settlement-name");
- // Store the world position for this label
- Vector3 worldPos = new Vector3(settlement.position.x, 0, settlement.position.y);
- worldPositions.Add(worldPos);
- // Position the label (will be updated continuously)
- Vector2 uiPosition = WorldToUIPosition(settlement.position);
- PositionLabel(label, uiPosition);
- // Manual styling to avoid CSS conflicts
- label.style.color = Color.white;
- label.style.fontSize = settlement.Type == SettlementType.Town ? 14 : 12;
- label.style.unityFontStyleAndWeight = settlement.Type == SettlementType.Town ? FontStyle.Bold : FontStyle.Normal;
- // Background for visibility
- label.style.backgroundColor = new Color(0, 0, 0, 0.7f);
- label.style.paddingLeft = 3;
- label.style.paddingRight = 3;
- label.style.paddingTop = 1;
- label.style.paddingBottom = 1;
- label.style.borderTopLeftRadius = 3;
- label.style.borderTopRightRadius = 3;
- label.style.borderBottomLeftRadius = 3;
- label.style.borderBottomRightRadius = 3;
- // CRITICAL: Allow clicks to pass through labels to the map beneath
- label.pickingMode = PickingMode.Ignore;
- // Ensure label is visible
- label.style.visibility = Visibility.Visible;
- label.style.display = DisplayStyle.Flex;
- mapContainer.Add(label);
- nameLabels.Add(label);
- // Debug verification
- if (debugMode)
- {
- Debug.Log($"MapLocationNameDisplay: Added settlement label '{label.text}' at world {worldPos} -> UI {uiPosition}. Container children: {mapContainer.childCount}. PickingMode: {label.pickingMode}");
- }
- }
- private void CreateFeatureLabel(GeographicFeature feature)
- {
- var label = new Label(feature.name);
- label.AddToClassList("location-name-label");
- label.AddToClassList($"{feature.type.ToString().ToLower()}-name");
- // Store the world position for this label
- Vector2Int featureCenter = feature.GetCenterPosition();
- Vector3 worldPos = new Vector3(featureCenter.x, 0, featureCenter.y);
- worldPositions.Add(worldPos);
- // Position the label at feature center (will be updated continuously)
- Vector2 uiPosition = WorldToUIPosition(featureCenter);
- PositionLabel(label, uiPosition);
- // Manual styling based on feature type to avoid CSS conflicts
- Color featureColor = GetFeatureColor(feature.type);
- label.style.color = featureColor;
- label.style.fontSize = GetFeatureFontSize(feature.type);
- label.style.unityFontStyleAndWeight = FontStyle.Normal;
- // Background for visibility
- label.style.backgroundColor = new Color(0, 0, 0, 0.6f);
- label.style.paddingLeft = 2;
- label.style.paddingRight = 2;
- label.style.paddingTop = 1;
- label.style.paddingBottom = 1;
- label.style.borderTopLeftRadius = 3;
- label.style.borderTopRightRadius = 3;
- label.style.borderBottomLeftRadius = 3;
- label.style.borderBottomRightRadius = 3;
- // CRITICAL: Allow clicks to pass through labels to the map beneath
- label.pickingMode = PickingMode.Ignore;
- // Ensure label is visible
- label.style.visibility = Visibility.Visible;
- label.style.display = DisplayStyle.Flex;
- // Add opacity for undiscovered features
- if (!feature.isDiscovered)
- {
- label.style.opacity = 0.6f;
- }
- mapContainer.Add(label);
- nameLabels.Add(label);
- // Debug verification
- if (debugMode)
- {
- Debug.Log($"MapLocationNameDisplay: Added feature label '{label.text}' to container. Container children: {mapContainer.childCount}. PickingMode: {label.pickingMode}");
- }
- }
- private Color GetFeatureColor(GeographicFeatureType type)
- {
- switch (type)
- {
- case GeographicFeatureType.Forest:
- return forestNameColor;
- case GeographicFeatureType.Lake:
- return lakeNameColor;
- case GeographicFeatureType.Plain:
- return plainNameColor;
- case GeographicFeatureType.Mountain:
- return mountainNameColor;
- case GeographicFeatureType.River:
- return riverNameColor;
- default:
- return Color.white;
- }
- }
- private int GetFeatureFontSize(GeographicFeatureType type)
- {
- switch (type)
- {
- case GeographicFeatureType.Mountain:
- return 13;
- case GeographicFeatureType.Forest:
- case GeographicFeatureType.Lake:
- return 12;
- case GeographicFeatureType.Plain:
- case GeographicFeatureType.River:
- return 11;
- default:
- return 12;
- }
- }
- private Vector2 WorldToUIPosition(Vector2Int worldPosition)
- {
- if (mainCamera == null || mapData == null)
- {
- if (debugMode) Debug.LogWarning("MapLocationNameDisplay: Camera or MapData is null in WorldToUIPosition");
- return Vector2.zero;
- }
- // Convert map grid coordinates to world position
- // Each tile is 1 unit in world space
- Vector3 worldPos = new Vector3(worldPosition.x, 0, worldPosition.y);
- // Convert world position to screen position
- Vector3 screenPos = mainCamera.WorldToScreenPoint(worldPos);
- // Convert screen position to UI coordinates
- if (mapContainer == null)
- {
- if (debugMode) Debug.LogWarning("MapLocationNameDisplay: MapContainer is null in WorldToUIPosition");
- return Vector2.zero;
- }
- // Get the container's bounds in screen space
- var containerBounds = mapContainer.worldBound;
- // Convert screen coordinates to UI element coordinates
- Vector2 uiPosition = new Vector2(
- screenPos.x - containerBounds.x,
- (Screen.height - screenPos.y) - containerBounds.y // Flip Y coordinate for UI space
- );
- if (debugMode && Random.Range(0f, 1f) < 0.05f) // Log occasionally to avoid spam
- {
- Debug.Log($"MapLocationNameDisplay: World {worldPosition} -> WorldPos {worldPos} -> Screen {screenPos} -> UI {uiPosition}");
- }
- return uiPosition;
- }
- private void PositionLabel(Label label, Vector2 uiPosition)
- {
- label.style.position = Position.Absolute;
- // The uiPosition is already calculated relative to the container
- label.style.left = uiPosition.x;
- label.style.top = uiPosition.y;
- if (debugMode && Random.Range(0f, 1f) < 0.05f) // Log occasionally to avoid spam
- {
- Debug.Log($"MapLocationNameDisplay: Positioned label '{label.text}' at ({uiPosition.x:F1}, {uiPosition.y:F1})");
- }
- }
- private void ClearAllLabels()
- {
- if (debugMode) Debug.Log($"MapLocationNameDisplay: Clearing {nameLabels.Count} existing labels");
- foreach (var label in nameLabels)
- {
- if (label.parent != null)
- {
- label.parent.Remove(label);
- }
- }
- nameLabels.Clear();
- worldPositions.Clear(); // Clear corresponding world positions
- if (debugMode && mapContainer != null)
- {
- Debug.Log($"MapLocationNameDisplay: After clearing, container has {mapContainer.childCount} children");
- }
- }
- private void StartPositionUpdates()
- {
- if (positionUpdateCoroutine != null)
- {
- StopCoroutine(positionUpdateCoroutine);
- }
- positionUpdateCoroutine = StartCoroutine(UpdateLabelPositions());
- }
- private void StopPositionUpdates()
- {
- if (positionUpdateCoroutine != null)
- {
- StopCoroutine(positionUpdateCoroutine);
- positionUpdateCoroutine = null;
- }
- }
- private IEnumerator UpdateLabelPositions()
- {
- while (true)
- {
- if (mainCamera != null && nameLabels.Count > 0 && worldPositions.Count == nameLabels.Count)
- {
- // Only update if camera has moved or zoom changed (more sensitive for smoother updates)
- bool cameraChanged = false;
- Vector3 currentCameraPos = mainCamera.transform.position;
- float currentCameraSize = mainCamera.orthographicSize;
- if (Vector3.Distance(currentCameraPos, lastCameraPosition) > 0.05f ||
- Mathf.Abs(currentCameraSize - lastCameraSize) > 0.05f)
- {
- cameraChanged = true;
- lastCameraPosition = currentCameraPos;
- lastCameraSize = currentCameraSize;
- }
- if (cameraChanged)
- {
- for (int i = 0; i < nameLabels.Count; i++)
- {
- if (nameLabels[i] != null && i < worldPositions.Count)
- {
- Vector3 worldPos = worldPositions[i];
- Vector3 screenPos = mainCamera.WorldToScreenPoint(worldPos);
- // Check if the position is in front of the camera
- if (screenPos.z > 0)
- {
- Vector2 uiPos = ScreenToUIPosition(screenPos);
- PositionLabel(nameLabels[i], uiPos);
- nameLabels[i].style.visibility = Visibility.Visible;
- }
- else
- {
- // Hide labels that are behind the camera
- nameLabels[i].style.visibility = Visibility.Hidden;
- }
- }
- }
- }
- }
- yield return new WaitForSeconds(updateFrequency);
- }
- }
- private Vector2 ScreenToUIPosition(Vector3 screenPos)
- {
- if (mapContainer == null) return Vector2.zero;
- var containerBounds = mapContainer.worldBound;
- // Convert screen coordinates to UI element coordinates
- Vector2 uiPosition = new Vector2(
- screenPos.x - containerBounds.x,
- (Screen.height - screenPos.y) - containerBounds.y // Flip Y coordinate for UI space
- );
- return uiPosition;
- }
- // Public methods for toggling different name types
- public void ToggleSettlementNames(bool show)
- {
- showSettlementNames = show;
- RefreshLocationNames();
- }
- public void ToggleForestNames(bool show)
- {
- showForestNames = show;
- RefreshLocationNames();
- }
- public void ToggleLakeNames(bool show)
- {
- showLakeNames = show;
- RefreshLocationNames();
- }
- public void TogglePlainNames(bool show)
- {
- showPlainNames = show;
- RefreshLocationNames();
- }
- public void ToggleMountainNames(bool show)
- {
- showMountainNames = show;
- RefreshLocationNames();
- }
- public void ToggleRiverNames(bool show)
- {
- showRiverNames = show;
- RefreshLocationNames();
- }
- [ContextMenu("Refresh Names")]
- public void RefreshNamesManual()
- {
- RefreshLocationNames();
- }
- [ContextMenu("Debug Info")]
- public void DebugInfo()
- {
- Debug.Log($"=== MapLocationNameDisplay Debug Info ===");
- Debug.Log($"MapData: {(mapData != null ? $"{mapData.Width}x{mapData.Height}" : "NULL")}");
- Debug.Log($"FeatureManager: {(featureManager != null ? "Found" : "NULL")}");
- Debug.Log($"MapContainer: {(mapContainer != null ? "Found" : "NULL")}");
- Debug.Log($"MapUIDocument: {(mapUIDocument != null ? "Found" : "NULL")}");
- Debug.Log($"Name Labels: {nameLabels.Count}");
- if (featureManager != null)
- {
- Debug.Log($"Geographic Features: {featureManager.GeographicFeatures.Count}");
- }
- if (mapData != null)
- {
- var settlements = mapData.GetAllSettlements();
- Debug.Log($"Settlements: {settlements.Count}");
- }
- }
- // IClickBlocker implementation - system disabled, never blocks clicks
- public bool IsBlockingClick(Vector2 screenPosition)
- {
- // System disabled - UI toolkit approach caused too many issues
- // Moving to 3D world space TextMeshPro approach instead
- return false;
- }
- }
|