Crash fixes
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
@@ -7,6 +8,6 @@ namespace Darkmatter.Core.Contracts.Services.Capture
|
||||
public interface ICaptureService
|
||||
{
|
||||
UniTask<byte[]> CapturePngAsync(GameObject captureObject, float scale,
|
||||
CancellationToken cancellationToken = default);
|
||||
Func<IDisposable> captureViewScopeFactory = null, CancellationToken cancellationToken = default);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Darkmatter.Features.Artbook
|
||||
{
|
||||
public record struct ArtbookEntry(string Id, string Name, Texture2D Thumbnail, DateTime UpdatedUtc);
|
||||
public record struct ArtbookEntry(string Id, string Name, DateTime UpdatedUtc);
|
||||
}
|
||||
|
||||
@@ -26,12 +26,13 @@ namespace Darkmatter.Features.Artbook
|
||||
private readonly IRewardedSaveGate _saveGate;
|
||||
|
||||
private readonly List<ArtbookEntry> _entries = new();
|
||||
private readonly List<Sprite> _ownedSprites = new();
|
||||
private readonly List<Texture2D> _ownedTextures = new();
|
||||
private readonly List<Sprite> _visibleSprites = new();
|
||||
private readonly List<Texture2D> _visibleTextures = new();
|
||||
private Action _onClose;
|
||||
private CancellationTokenSource _cts;
|
||||
private IDisposable _openSubscription;
|
||||
private int _currentSpread;
|
||||
private int _renderVersion;
|
||||
|
||||
public ArtbookPresenter(
|
||||
ArtbookView view,
|
||||
@@ -75,33 +76,40 @@ namespace Darkmatter.Features.Artbook
|
||||
|
||||
private async UniTaskVoid LoadAndShowAsync(CancellationToken ct)
|
||||
{
|
||||
ClearOwnedAssets();
|
||||
_entries.Clear();
|
||||
_currentSpread = 0;
|
||||
|
||||
await _catalog.FetchAsync();
|
||||
if (ct.IsCancellationRequested) return;
|
||||
|
||||
foreach (var id in _catalog.AllTemplateIds)
|
||||
try
|
||||
{
|
||||
ClearVisibleAssets();
|
||||
_entries.Clear();
|
||||
_currentSpread = 0;
|
||||
|
||||
await _catalog.FetchAsync();
|
||||
if (ct.IsCancellationRequested) return;
|
||||
|
||||
var progress = _progression.GetProgress(id);
|
||||
if (progress is not { hasThumbnail: true }) continue;
|
||||
foreach (var id in _catalog.AllTemplateIds)
|
||||
{
|
||||
if (ct.IsCancellationRequested) return;
|
||||
|
||||
var texture = await _progression.GetCachedThumbnailAsync(id);
|
||||
if (ct.IsCancellationRequested) return;
|
||||
if (texture == null) continue;
|
||||
var progress = _progression.GetProgress(id);
|
||||
if (progress is not { hasThumbnail: true }) continue;
|
||||
|
||||
var template = await _catalog.LoadAsync(id);
|
||||
if (ct.IsCancellationRequested) return;
|
||||
var template = await _catalog.LoadAsync(id);
|
||||
if (ct.IsCancellationRequested) return;
|
||||
if (template == null) continue;
|
||||
|
||||
_ownedTextures.Add(texture);
|
||||
_entries.Add(new ArtbookEntry(id, template.DisplayName, texture, progress.Value.UpdatedUtc));
|
||||
_entries.Add(new ArtbookEntry(id, template.DisplayName, progress.Value.UpdatedUtc));
|
||||
}
|
||||
|
||||
_entries.Sort((a, b) => b.UpdatedUtc.CompareTo(a.UpdatedUtc));
|
||||
RenderSpread();
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
// Opening/closing the art book can cancel the load at any await point.
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError($"[Artbook] Failed to load entries: {e}");
|
||||
}
|
||||
|
||||
_entries.Sort((a, b) => b.UpdatedUtc.CompareTo(a.UpdatedUtc));
|
||||
RenderSpread();
|
||||
}
|
||||
|
||||
private void HandlePrevSpreadClicked()
|
||||
@@ -122,7 +130,7 @@ namespace Darkmatter.Features.Artbook
|
||||
|
||||
private void RenderSpread()
|
||||
{
|
||||
_view.SetSpread(GetLeftEntry(), SpriteFor(GetLeftEntry()), GetRightEntry(), SpriteFor(GetRightEntry()));
|
||||
RenderSpreadAsync(++_renderVersion, _cts?.Token ?? CancellationToken.None).Forget();
|
||||
_view.SetNavigation(_currentSpread > 0, _currentSpread < TotalSpreads - 1);
|
||||
}
|
||||
|
||||
@@ -138,13 +146,51 @@ namespace Darkmatter.Features.Artbook
|
||||
return idx < _entries.Count ? _entries[idx] : null;
|
||||
}
|
||||
|
||||
private Sprite SpriteFor(ArtbookEntry? entry)
|
||||
private async UniTaskVoid RenderSpreadAsync(int version, CancellationToken ct)
|
||||
{
|
||||
if (!entry.HasValue) return null;
|
||||
var tex = entry.Value.Thumbnail;
|
||||
var left = GetLeftEntry();
|
||||
var right = GetRightEntry();
|
||||
ClearVisibleAssets();
|
||||
_view.SetSpread(left, null, right, null);
|
||||
|
||||
try
|
||||
{
|
||||
var leftSprite = await SpriteForAsync(left, version, ct);
|
||||
var rightSprite = await SpriteForAsync(right, version, ct);
|
||||
if (ct.IsCancellationRequested || version != _renderVersion)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_view.SetSpread(left, leftSprite, right, rightSprite);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
if (version == _renderVersion) ClearVisibleAssets();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (version == _renderVersion) ClearVisibleAssets();
|
||||
Debug.LogError($"[Artbook] Failed to render spread: {e}");
|
||||
}
|
||||
}
|
||||
|
||||
private async UniTask<Sprite> SpriteForAsync(ArtbookEntry? entry, int version, CancellationToken ct)
|
||||
{
|
||||
if (!entry.HasValue || ct.IsCancellationRequested || version != _renderVersion) return null;
|
||||
|
||||
var tex = await _progression.GetCachedThumbnailAsync(entry.Value.Id);
|
||||
if (ct.IsCancellationRequested || version != _renderVersion)
|
||||
{
|
||||
if (tex != null) UnityEngine.Object.Destroy(tex);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (tex == null) return null;
|
||||
|
||||
var sprite = Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), new Vector2(0.5f, 0.5f), 100f);
|
||||
_ownedSprites.Add(sprite);
|
||||
_visibleTextures.Add(tex);
|
||||
_visibleSprites.Add(sprite);
|
||||
return sprite;
|
||||
}
|
||||
|
||||
@@ -153,13 +199,32 @@ namespace Darkmatter.Features.Artbook
|
||||
|
||||
private async UniTaskVoid SaveToGalleryAsync(ArtbookEntry? entry)
|
||||
{
|
||||
if (!entry.HasValue || entry.Value.Thumbnail == null) return;
|
||||
var ct = _cts?.Token ?? CancellationToken.None;
|
||||
// Same kid-friendly prompt + rewarded ad as the gameplay save button.
|
||||
if (!await _saveGate.RequestSaveAsync(ct)) return;
|
||||
await _gallery.SaveImageAsync(entry.Value.Thumbnail, entry.Value.Name, ct);
|
||||
// The art book has no success popup of its own, so use the shared toast.
|
||||
await _saveGate.ShowSavedAsync(ct);
|
||||
Texture2D texture = null;
|
||||
try
|
||||
{
|
||||
if (!entry.HasValue) return;
|
||||
var ct = _cts?.Token ?? CancellationToken.None;
|
||||
// Same kid-friendly prompt + rewarded ad as the gameplay save button.
|
||||
if (!await _saveGate.RequestSaveAsync(ct)) return;
|
||||
texture = await _progression.GetCachedThumbnailAsync(entry.Value.Id);
|
||||
if (texture == null) return;
|
||||
|
||||
await _gallery.SaveImageAsync(texture, entry.Value.Name, ct);
|
||||
// The art book has no success popup of its own, so use the shared toast.
|
||||
await _saveGate.ShowSavedAsync(ct);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
// The art book was closed or replaced while saving.
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError($"[Artbook] Failed to save page: {e}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (texture != null) UnityEngine.Object.Destroy(texture);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleLeftEditClicked() => OpenForEdit(GetLeftEntry());
|
||||
@@ -169,27 +234,43 @@ namespace Darkmatter.Features.Artbook
|
||||
{
|
||||
if (!entry.HasValue) return;
|
||||
_eventBus.Publish(new DrawingSelectedSignal(entry.Value.Id));
|
||||
StopActiveWork();
|
||||
_view.Hide();
|
||||
}
|
||||
|
||||
private void HandleBackButtonClicked()
|
||||
{
|
||||
_onClose?.Invoke();
|
||||
StopActiveWork();
|
||||
_view.Hide();
|
||||
}
|
||||
|
||||
private void HandleColorbookButtonClicked()
|
||||
{
|
||||
_eventBus.Publish(new OpenColorBookSignal());
|
||||
StopActiveWork();
|
||||
_view.Hide();
|
||||
}
|
||||
|
||||
private void StopActiveWork()
|
||||
{
|
||||
_renderVersion++;
|
||||
_cts?.Cancel();
|
||||
_view.SetSpread(null, null, null, null);
|
||||
ClearVisibleAssets();
|
||||
}
|
||||
|
||||
private void ClearOwnedAssets()
|
||||
{
|
||||
foreach (var s in _ownedSprites) UnityEngine.Object.Destroy(s);
|
||||
foreach (var t in _ownedTextures) UnityEngine.Object.Destroy(t);
|
||||
_ownedSprites.Clear();
|
||||
_ownedTextures.Clear();
|
||||
ClearVisibleAssets();
|
||||
}
|
||||
|
||||
private void ClearVisibleAssets()
|
||||
{
|
||||
foreach (var s in _visibleSprites) UnityEngine.Object.Destroy(s);
|
||||
foreach (var t in _visibleTextures) UnityEngine.Object.Destroy(t);
|
||||
_visibleSprites.Clear();
|
||||
_visibleTextures.Clear();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
@@ -208,4 +289,4 @@ namespace Darkmatter.Features.Artbook
|
||||
ClearOwnedAssets();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,12 +51,11 @@ namespace Darkmatter.Features.Capture
|
||||
// A null result keeps the existing thumbnail and skips the gallery write (both no-op on null).
|
||||
if (_coloring.IsPlayingCompletionAnimation) return null;
|
||||
|
||||
byte[] png;
|
||||
using (_coloring.UseNonZoomedView())
|
||||
{
|
||||
png = await _captureService.CapturePngAsync(_refs.PaperRoot.gameObject, _config.CaptureScale, ct);
|
||||
}
|
||||
|
||||
var png = await _captureService.CapturePngAsync(
|
||||
_refs.PaperRoot.gameObject,
|
||||
_config.CaptureScale,
|
||||
_coloring.UseNonZoomedView,
|
||||
ct);
|
||||
if (!saveToGallery || png == null || png.Length == 0) return png;
|
||||
|
||||
var tex = new Texture2D(2, 2, TextureFormat.RGBA32, mipChain: false);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using Cysharp.Threading.Tasks;
|
||||
@@ -5,6 +6,7 @@ using Darkmatter.Core.Contracts.Services.Camera;
|
||||
using Darkmatter.Core.Contracts.Services.Capture;
|
||||
using UnityEngine;
|
||||
using CameraType = Darkmatter.Core.Enums.Services.Camera.CameraType;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace Darkmatter.Services.Capture
|
||||
{
|
||||
@@ -15,7 +17,7 @@ namespace Darkmatter.Services.Capture
|
||||
public CaptureService(ICameraService cameraService) => _cameraService = cameraService;
|
||||
|
||||
public async UniTask<byte[]> CapturePngAsync(GameObject captureObject, float scale,
|
||||
CancellationToken cancellationToken = default)
|
||||
Func<IDisposable> captureViewScopeFactory = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (captureObject == null) return null;
|
||||
var paperRT = captureObject.transform as RectTransform;
|
||||
@@ -26,10 +28,6 @@ namespace Darkmatter.Services.Capture
|
||||
int sw = Screen.width;
|
||||
int sh = Screen.height;
|
||||
|
||||
Rect crop = ComputeCropRect(captureObject, sw, sh);
|
||||
int cropW = Mathf.Max(1, (int)crop.width);
|
||||
int cropH = Mathf.Max(1, (int)crop.height);
|
||||
|
||||
var prevFlags = cam.clearFlags;
|
||||
var prevBg = cam.backgroundColor;
|
||||
var prevTarget = cam.targetTexture;
|
||||
@@ -41,15 +39,22 @@ namespace Darkmatter.Services.Capture
|
||||
|
||||
List<Canvas> disabledCanvases = null;
|
||||
List<UnityEngine.UI.Graphic> disabledGraphics = null;
|
||||
IDisposable captureViewScope = null;
|
||||
|
||||
try
|
||||
{
|
||||
await UniTask.WaitForEndOfFrame(cancellationToken);
|
||||
|
||||
captureViewScope = captureViewScopeFactory?.Invoke();
|
||||
|
||||
disabledCanvases = DisableOtherRootCanvases(paperCanvas);
|
||||
disabledGraphics = HideNonPaperGraphics(paperRT);
|
||||
HideBackdropGraphics(paperRT, disabledGraphics);
|
||||
|
||||
Rect crop = ComputeCropRect(captureObject, sw, sh);
|
||||
int cropW = Mathf.Max(1, (int)crop.width);
|
||||
int cropH = Mathf.Max(1, (int)crop.height);
|
||||
|
||||
cam.clearFlags = CameraClearFlags.SolidColor;
|
||||
cam.backgroundColor = new Color(0f, 0f, 0f, 0f);
|
||||
cam.targetTexture = rt;
|
||||
@@ -67,6 +72,8 @@ namespace Darkmatter.Services.Capture
|
||||
fullScreen.ReadPixels(new Rect(0, 0, sw, sh), 0, 0);
|
||||
fullScreen.Apply();
|
||||
RenderTexture.active = prevActive;
|
||||
captureViewScope?.Dispose();
|
||||
captureViewScope = null;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -118,6 +125,7 @@ namespace Darkmatter.Services.Capture
|
||||
foreach (var c in disabledCanvases)
|
||||
if (c != null)
|
||||
c.enabled = true;
|
||||
captureViewScope?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,4 +225,4 @@ namespace Darkmatter.Services.Capture
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user