Aetheria/Assets/Scripts/UI/Menu/MapRenderer.cs
2026-06-25 18:09:33 +01:00

236 lines
7.7 KiB
C#

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using GameCult.Aetheria.State.Verse;
using TMPro;
using UnityEngine;
using Unity.Mathematics;
using UnityEngine.UI;
using static Unity.Mathematics.math;
using int2 = Unity.Mathematics.int2;
public class MapRenderer : MonoBehaviour
{
public ZoneRenderer ZoneRenderer;
public TextMeshProUGUI Title;
public Camera MapOverlayCamera;
public Camera GravityCamera;
public Camera TintCamera;
public Camera InfluenceCamera;
public Image OverlayDisplay;
public Image GravityDisplay;
public Image TintDisplay;
public Image InfluenceDisplay;
public float Scale;
public float2 Position;
public float IconSize = 1f/128;
private RectTransform _rect;
private RenderTexture _mapTexture;
private RenderTexture _gravityTexture;
private RenderTexture _tintTexture;
private RenderTexture _influenceTexture;
private int2 _size;
private bool _init;
private AetheriaClient _client;
private string _clientStatePath = "";
private AetheriaRuntimeObjectsViewportDocument _objectsViewport;
private AetheriaRuntimeGravityViewportDocument _gravityViewport;
private float _nextViewportRefreshTime;
void Start()
{
_rect = GetComponent<RectTransform>();
}
private void OnEnable()
{
_init = true;
MapOverlayCamera.gameObject.SetActive(true);
GravityCamera.gameObject.SetActive(true);
TintCamera.gameObject.SetActive(true);
InfluenceCamera.gameObject.SetActive(true);
RefreshViewportDocuments(force: true);
// If hiding minimap asteroids, turn them back on for the map screen
if (!ResolveShowAsteroidsInMinimap())
ZoneRenderer.ShowAsteroidUI = true;
}
private void OnDisable()
{
if (_mapTexture != null)
{
ReleaseTextures();
}
MapOverlayCamera.gameObject.SetActive(false);
GravityCamera.gameObject.SetActive(false);
TintCamera.gameObject.SetActive(false);
InfluenceCamera.gameObject.SetActive(false);
// If hiding minimap asteroids, turn them back off when leaving the map screen
if (!ResolveShowAsteroidsInMinimap())
ZoneRenderer.ShowAsteroidUI = false;
}
private void OnDestroy()
{
DisposeClient();
}
void ReleaseTextures()
{
_mapTexture.Release();
_mapTexture = null;
_gravityTexture.Release();
_gravityTexture = null;
_tintTexture.Release();
_tintTexture = null;
_influenceTexture.Release();
_influenceTexture = null;
}
void LateUpdate()
{
var size = int2(Screen.width, Screen.height);
if (_init || size.x != _size.x || size.y != _size.y)
{
_init = false;
_size = size;
if (_mapTexture != null)
{
ReleaseTextures();
}
_mapTexture = new RenderTexture(_size.x, _size.y, 0, RenderTextureFormat.Default);
MapOverlayCamera.targetTexture = _mapTexture;
OverlayDisplay.material.SetTexture("_DetailTex", _mapTexture);
_gravityTexture = new RenderTexture(_size.x, _size.y, 0, RenderTextureFormat.RFloat);
GravityCamera.targetTexture = _gravityTexture;
GravityDisplay.material.SetTexture("_DetailTex", _gravityTexture);
_tintTexture = new RenderTexture(_size.x / 2, _size.y / 2, 0, RenderTextureFormat.RGB111110Float);
TintCamera.targetTexture = _tintTexture;
TintDisplay.material.SetTexture("_DetailTex", _tintTexture);
_influenceTexture = new RenderTexture(_size.x, _size.y, 0, RenderTextureFormat.RFloat);
InfluenceCamera.targetTexture = _influenceTexture;
InfluenceDisplay.material.SetTexture("_DetailTex", _influenceTexture);
}
var pos = ((Vector2) Position).Flatland(1);
MapOverlayCamera.transform.position = pos;
MapOverlayCamera.orthographicSize = _size.y * Scale * .5f;
GravityCamera.transform.position = pos;
GravityCamera.orthographicSize = _size.y * Scale * .5f;
GravityDisplay.material.SetFloat("_Scale", Scale / 2);
TintCamera.transform.position = pos;
TintCamera.orthographicSize = _size.y * Scale * .5f;
InfluenceCamera.transform.position = pos;
InfluenceCamera.orthographicSize = _size.y * Scale * .5f;
ZoneRenderer.SetIconSize(IconSize * Scale);
RefreshViewportDocuments(force: false);
}
private void RefreshViewportDocuments(bool force)
{
if (!force && Time.unscaledTime < _nextViewportRefreshTime)
return;
_nextViewportRefreshTime = Time.unscaledTime + .5f;
try
{
var client = ResolveClient();
var viewport = ResolveViewportBounds();
_objectsViewport = client
.ObjectsViewportAsync(viewport)
.GetAwaiter()
.GetResult();
_gravityViewport = client
.GravityViewportAsync(viewport)
.GetAwaiter()
.GetResult();
var zoneName = string.IsNullOrWhiteSpace(_objectsViewport?.ZoneName)
? "Unknown"
: _objectsViewport.ZoneName;
Title.text = $"Zone: {zoneName}";
}
catch (Exception ex)
{
Debug.LogWarning($"Failed to read Aetheria map viewport from local Verse state: {ex.Message}");
Title.text = "Zone: Unknown";
}
}
private AetheriaRuntimeRtsViewportBounds ResolveViewportBounds()
{
var screenHeight = _size.y <= 0 ? Math.Max(1, Screen.height) : _size.y;
var screenWidth = _size.x <= 0 ? Math.Max(1, Screen.width) : _size.x;
var halfHeight = screenHeight * Scale * .5f;
var halfWidth = screenWidth * Scale * .5f;
return new AetheriaRuntimeRtsViewportBounds
{
MinX = Position.x - halfWidth,
MinY = Position.y - halfHeight,
MaxX = Position.x + halfWidth,
MaxY = Position.y + halfHeight
};
}
private bool ResolveShowAsteroidsInMinimap()
{
try
{
return ResolveClient()
.PlayerSettingsAsync()
.GetAwaiter()
.GetResult()
?.ShowAsteroidsInMinimap ?? false;
}
catch (Exception ex)
{
Debug.LogWarning($"Failed to read Aetheria map graphics settings from local Verse state: {ex.Message}");
return false;
}
}
private AetheriaClient ResolveClient()
{
var gameDataDirectory = new DirectoryInfo(Path.Combine(Application.dataPath, "..", "GameData"));
var stateBoot = AetheriaRuntimeStateBoot.Inspect(gameDataDirectory);
if (_client != null && string.Equals(_clientStatePath, stateBoot.StateFilePath, StringComparison.Ordinal))
return _client;
DisposeClient();
_client = AetheriaClient
.OpenLocalAsync(
gameDataDirectory,
"unity-map-renderer",
"local",
pullOnOpen: true)
.GetAwaiter()
.GetResult();
_clientStatePath = stateBoot.StateFilePath;
return _client;
}
private void DisposeClient()
{
_client?.Dispose();
_client = null;
_clientStatePath = "";
}
}