Commit 47b99886 authored by ElderLich's avatar ElderLich

Bug Fix: Fix MyCard watch avatar refresh on recycled UI rows

Prevents MissingReferenceException spam when MyCard watch-list items are destroyed or recycled during async avatar loading. Avatar downloads now respect row lifetime/cancellation and only update RawImage targets that still exist.
parent f320ee58
......@@ -7,6 +7,7 @@ using System.IO;
using System.Linq;
using System.Net;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Networking;
......@@ -224,16 +225,19 @@ namespace MDPro3
#region Online
public static async Task<Texture2D> DownloadImageAsync(string url)
public static async Task<Texture2D> DownloadImageAsync(string url, CancellationToken cancellationToken = default)
{
using var request = UnityWebRequestTexture.GetTexture(url);
request.SetRequestHeader("User-Agent", "MDPro3/" + Application.version + " (" + System.Environment.OSVersion.ToString() + "); Unity/" + Application.unityVersion);
var send = request.SendWebRequest();
await TaskUtility.WaitUntil(() => send.isDone);
while (!send.isDone)
await TaskUtility.WaitOneFrame(cancellationToken);
if (!Application.isPlaying)
return null;
cancellationToken.ThrowIfCancellationRequested();
if (request.result == UnityWebRequest.Result.Success)
{
return DownloadHandlerTexture.GetContent(request);
......
using System;
using System.Threading;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Networking;
......@@ -113,8 +114,10 @@ namespace MDPro3.Net
}
}
public static async UniTask<Texture2D> GetAvatarAsync(string userName)
public static async UniTask<Texture2D> GetAvatarAsync(string userName, CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
if(!Directory.Exists(avatarSavePath))
Directory.CreateDirectory(avatarSavePath);
......@@ -137,6 +140,7 @@ namespace MDPro3.Net
return cachedAvatars[avatarName];
var pic = await TextureManager.LoadPicFromFileAsync(fullPath);
cancellationToken.ThrowIfCancellationRequested();
lock (cachedAvatars)
if (!cachedAvatars.ContainsKey(avatarName))
......@@ -148,7 +152,7 @@ namespace MDPro3.Net
using(var request = UnityWebRequest.Get(userUrl.Replace("{username}", userName)))
{
await request.SendWebRequest();
await request.SendWebRequest().WithCancellation(cancellationToken);
if (request.result == UnityWebRequest.Result.Success)
{
avatarAddress = JsonUtility.FromJson<MyCardRoomUserInfo>(request.downloadHandler.text).user.avatar;
......@@ -160,8 +164,11 @@ namespace MDPro3.Net
}
}
var requestAvatar = Tools.DownloadImageAsync(avatarAddress);
cancellationToken.ThrowIfCancellationRequested();
var requestAvatar = Tools.DownloadImageAsync(avatarAddress, cancellationToken);
await requestAvatar;
cancellationToken.ThrowIfCancellationRequested();
Texture2D downloadImage = requestAvatar.Result;
if (downloadImage == null)
return null;
......
......@@ -2,9 +2,11 @@ using MDPro3.Net;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using UnityEngine.EventSystems;
using MDPro3.Servant;
using MDPro3.UI.ServantUI;
......@@ -62,14 +64,33 @@ namespace MDPro3.UI
protected override async UniTask RefreshAsync()
{
refreshed = false;
var cancellationToken = cts?.Token ?? destroyCancellationToken;
var face0 = Manager.GetElement<RawImage>("Face0");
var face1 = Manager.GetElement<RawImage>("Face1");
Manager.GetElement<RawImage>("Face0").texture = Appearance.defaultFace0.texture;
Manager.GetElement<RawImage>("Face1").texture = Appearance.defaultFace1.texture;
if (face0 != null)
face0.texture = Appearance.defaultFace0.texture;
if (face1 != null)
face1.texture = Appearance.defaultFace1.texture;
Manager.GetElement<RawImage>("Face0").texture = await MyCard.GetAvatarAsync(player0Name);
Manager.GetElement<RawImage>("Face1").texture = await MyCard.GetAvatarAsync(player1Name);
try
{
var avatar0 = await MyCard.GetAvatarAsync(player0Name, cancellationToken);
if (!cancellationToken.IsCancellationRequested && face0 != null)
face0.texture = avatar0;
var avatar1 = await MyCard.GetAvatarAsync(player1Name, cancellationToken);
if (!cancellationToken.IsCancellationRequested && face1 != null)
face1.texture = avatar1;
refreshed = true;
refreshed = true;
}
catch (OperationCanceledException)
{
}
catch (MissingReferenceException)
{
}
}
protected override void CallToggleOnEvent()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment