using System; using System.Collections; using System.Collections.Generic; using System.IO; using BITKit.Entities; using BITKit.WorldNode; using Cysharp.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Unity.Mathematics; using UnityEngine; using YamlDotNet.Serialization; using Object = UnityEngine.Object; namespace Net.Project.B.World { public class UnitySnapshotService : ISnapshotService { private readonly IEntitiesService _entitiesService; private readonly ILogger _logger; private readonly ISerializer _serializer; private readonly IDeserializer _deserializer; public UnitySnapshotService(ISerializer serializer, IDeserializer deserializer, ILogger logger, IEntitiesService entitiesService) { _serializer = serializer; _deserializer = deserializer; _logger = logger; _entitiesService = entitiesService; } public string Directory { get; } = Path.Combine(Application.persistentDataPath, "Snapshots").Replace('/', '\\'); public async UniTask Snapshot(float3 position, quaternion rotation, int fov) { var renderTexture = new RenderTexture(Screen.width, Screen.height, 32); var camera = Camera.main; if (!camera) throw new DriveNotFoundException("未找到MainCamera"); camera.targetTexture = renderTexture; camera.Render(); camera.targetTexture = null; var screenshot = new Texture2D(renderTexture.width, renderTexture.height, TextureFormat.RGBA32, false); RenderTexture.active = renderTexture; screenshot.ReadPixels(new Rect(0, 0, renderTexture.width, renderTexture.height), 0, 0); screenshot.Apply(); RenderTexture.active = null; Object.Destroy(renderTexture); var bytes = screenshot.EncodeToPNG(); var fileName = DateTime.Now.Ticks; var path = Path.Combine(Directory, fileName + ".png"); new DirectoryInfo(Directory).Create(); await File.WriteAllBytesAsync(path, bytes); var data = new SnapshotData { FileName = null, Name = null, Description = null, CreateTime = default, Position = default, Rotation = default }; data.FileName = path; data.Name = "无标题"; data.Description = "无描述"; data.CreateTime = DateTime.Now; data.Position = camera.transform.position; data.Rotation = camera.transform.rotation; if (Physics.Raycast(camera.transform.position, camera.transform.forward, out var hit)) { if(_entitiesService.Entities.TryGetValue(hit.transform.gameObject.GetInstanceID(),out var hitEntity) && hitEntity.ServiceProvider.GetService() is {} node) { data.Name = node.Name; data.Description = node.Description; _logger.LogInformation($"相机命中了:{hit.transform.name}@{node.Name}:{node.Description}"); } else { _logger.LogInformation($"相机命中了:{hit.transform.name},但无有效目标"); } } var yaml = _serializer.Serialize(data); await File.WriteAllTextAsync(Path.Combine(Directory, fileName + ".yaml"), yaml); await UniTask.SwitchToMainThread(); OnSnapshot?.Invoke(data); return data; } public async UniTask> GetSnapshots() { var list = new List(); new DirectoryInfo(Directory).Create(); foreach (var fileInfo in new DirectoryInfo(Directory).GetFiles("*.yaml")) { var yaml = await File.ReadAllTextAsync(fileInfo.FullName); var data = _deserializer.Deserialize(yaml); list.Add(data); } return list; } public static event Action OnSnapshot; event Action ISnapshotService.OnSnapshot { add => OnSnapshot += value; remove => OnSnapshot -= value; } } }