253 lines
8.2 KiB
C#
253 lines
8.2 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using BITKit;
|
|
using BITKit.Entities;
|
|
using BITKit.WorldNode;
|
|
using Cysharp.Threading.Tasks;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Microsoft.Extensions.Logging;
|
|
using Net.Project.B.World;
|
|
using Project.B.Map;
|
|
using Unity.Mathematics;
|
|
using UnityEngine;
|
|
using UnityEngine.AI;
|
|
using UnityEngine.SceneManagement;
|
|
using Object = UnityEngine.Object;
|
|
|
|
namespace Net.Project.B.WorldNode
|
|
{
|
|
public class UnityMinimapService:IWorldMinimapService
|
|
{
|
|
public string Directory { get; } = Path.Combine(Application.persistentDataPath, "Overviews").Replace('/', '\\');
|
|
|
|
private readonly IGameMapService _gameMapService;
|
|
private readonly ILogger<UnityMinimapService> _logger;
|
|
private readonly IEntitiesService _entitiesService;
|
|
|
|
private UniTaskCompletionSource _waitMinimap=new();
|
|
|
|
public object MinimapObject { get; private set; }
|
|
public float2 Offset { get;private set; }
|
|
public int Size { get; private set;}
|
|
public event Action OnMinimapInitialized;
|
|
|
|
public UnityMinimapService(ILogger<UnityMinimapService> logger, IEntitiesService entitiesService, IGameMapService gameMapService)
|
|
{
|
|
_logger = logger;
|
|
_entitiesService = entitiesService;
|
|
_gameMapService = gameMapService;
|
|
_entitiesService.OnAdd += OnNodeRegistered;
|
|
|
|
_gameMapService.OnMapChanged += OnMapChanged;
|
|
}
|
|
|
|
private async void OnMapChanged(Guid arg1, string arg2)
|
|
{
|
|
if(string.IsNullOrEmpty(arg2))return;
|
|
|
|
_waitMinimap?.TrySetCanceled();
|
|
|
|
_waitMinimap = new();
|
|
|
|
try
|
|
{
|
|
await _waitMinimap.Task.Timeout(TimeSpan.FromSeconds(1));
|
|
|
|
return;
|
|
}
|
|
catch(OperationCanceledException){}
|
|
catch (TimeoutException)
|
|
{
|
|
_logger.LogInformation("未找到预设Minimap,开始自动创建");
|
|
}
|
|
|
|
foreach (var scriptableGameMapData in _entitiesService.QueryComponents<ScriptableGameMapData>().ToArray())
|
|
{
|
|
if(scriptableGameMapData.MapAddress != arg2)continue;
|
|
if(scriptableGameMapData.MapOverview is not Object{ }obj)continue;
|
|
if(!obj)continue;
|
|
|
|
MinimapObject = scriptableGameMapData.MapOverview;
|
|
|
|
Offset = scriptableGameMapData.Offset;
|
|
Size = scriptableGameMapData.Size;
|
|
|
|
|
|
OnMinimapInitialized?.Invoke();
|
|
|
|
_logger.LogInformation($"从{nameof(ScriptableGameMapData)}中找到了Minimap");
|
|
|
|
return;
|
|
}
|
|
|
|
var worldBounds = new Bounds(default,Vector3.one*32);
|
|
|
|
foreach (var rootGameObject in SceneManager.GetActiveScene().GetRootGameObjects())
|
|
{
|
|
foreach (var collider in rootGameObject.GetComponentsInChildren<Collider>())
|
|
{
|
|
var bounds = collider.bounds;
|
|
|
|
if(bounds.size.GetLength()>32 || collider.gameObject.isStatic)continue;
|
|
|
|
worldBounds.Encapsulate(bounds);
|
|
}
|
|
}
|
|
|
|
var size = worldBounds.size;
|
|
|
|
var camera = new GameObject().AddComponent<Camera>();
|
|
|
|
//camera.cullingMask = LayerMask.NameToLayer("Default");
|
|
camera.orthographicSize = math.max(size.x,size.z);
|
|
|
|
camera.transform.position = worldBounds.center + Vector3.up * camera.orthographicSize;
|
|
camera.transform.localEulerAngles = new(90, 0, 0);
|
|
|
|
camera.orthographic = true;
|
|
|
|
var rendererTexture = new RenderTexture( (int)camera.orthographicSize*8, (int)camera.orthographicSize*8, 32);
|
|
|
|
camera.targetTexture = rendererTexture;
|
|
|
|
camera.Render();
|
|
|
|
var cameraPosition = camera.transform.position;
|
|
|
|
Offset = new(cameraPosition.x, cameraPosition.z);
|
|
|
|
Size = (int)camera.orthographicSize;
|
|
|
|
camera.targetTexture = null;
|
|
|
|
SaveRendererTextureToPng(_gameMapService.CurrentMap,rendererTexture);
|
|
|
|
Object.Destroy(camera.gameObject);
|
|
|
|
MinimapObject = rendererTexture;
|
|
|
|
OnMinimapInitialized?.Invoke();
|
|
}
|
|
|
|
private async void OnNodeRegistered(IEntity entity)
|
|
{
|
|
try
|
|
{
|
|
if(entity.ServiceProvider.GetService<UnityMinimapNode>() is not {}minimapNode)return;
|
|
|
|
|
|
if (entity.ServiceProvider.GetService<Camera>() is not { } camera)
|
|
{
|
|
if (entity.ServiceProvider.GetService<Transform>() is {} transform && transform.TryGetComponent<Camera>(out camera) )
|
|
{
|
|
|
|
}
|
|
else
|
|
{
|
|
_logger.LogWarning("未找到Camera,跳过");
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
await UniTask.NextFrame();
|
|
|
|
if (!camera)
|
|
{
|
|
_logger.LogWarning("Camera 已被销毁,跳过");
|
|
return;
|
|
}
|
|
|
|
GameObject sample = null;
|
|
|
|
if(false)
|
|
{
|
|
|
|
NavMeshTriangulation navMeshTriangluation = NavMesh.CalculateTriangulation();
|
|
int[] triangles = navMeshTriangluation.indices;
|
|
Vector3[] vertices = navMeshTriangluation.vertices;
|
|
|
|
var mesh = new Mesh();
|
|
mesh.vertices = vertices;
|
|
mesh.triangles = triangles;
|
|
mesh.RecalculateNormals();
|
|
mesh.RecalculateBounds();
|
|
mesh.Optimize();
|
|
|
|
|
|
sample = new GameObject();
|
|
sample.transform.position = default;
|
|
sample.transform.rotation = default;
|
|
sample.AddComponent<MeshFilter>().mesh = mesh;
|
|
sample.AddComponent<MeshRenderer>().material = new Material(Shader.Find("Unlit/Color"))
|
|
{
|
|
color = new Color32(64, 64, 64, 255),
|
|
renderQueue = 4000
|
|
};
|
|
|
|
}
|
|
|
|
camera.Render();
|
|
|
|
|
|
SaveRendererTextureToPng(_gameMapService.CurrentMap,camera.targetTexture);
|
|
|
|
await UniTask.NextFrame();
|
|
|
|
if(sample)
|
|
Object.Destroy(sample);
|
|
|
|
MinimapObject = camera.targetTexture;
|
|
|
|
camera.targetTexture = null;
|
|
|
|
Object.Destroy(camera.gameObject);
|
|
|
|
|
|
|
|
_logger.LogInformation("已获取到Minimap");
|
|
|
|
var cameraPosition = camera.transform.position;
|
|
|
|
Offset = new(cameraPosition.x, cameraPosition.z);
|
|
|
|
Size = (int)camera.orthographicSize;
|
|
|
|
OnMinimapInitialized?.Invoke();
|
|
|
|
_waitMinimap.TrySetResult();
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
_logger.LogError(e,e.Message);
|
|
}
|
|
|
|
}
|
|
|
|
private void SaveRendererTextureToPng(string name,RenderTexture rendererTexture)
|
|
{
|
|
var screenshot = new Texture2D(rendererTexture.width, rendererTexture.height, TextureFormat.RGBA32, false);
|
|
RenderTexture.active = rendererTexture;
|
|
screenshot.ReadPixels(new Rect(0, 0, rendererTexture.width, rendererTexture.height), 0, 0);
|
|
screenshot.Apply();
|
|
RenderTexture.active = null;
|
|
|
|
|
|
var bytes = screenshot.EncodeToPNG();
|
|
|
|
var fileName = DateTime.Now.Ticks;
|
|
|
|
var path = Path.Combine(Directory,$"{name}_{fileName}.png");
|
|
|
|
new DirectoryInfo(Directory).Create();
|
|
|
|
File.WriteAllBytes(path, bytes);
|
|
}
|
|
|
|
|
|
}
|
|
}
|
|
|