Commit 783fa82a authored by ElderLich's avatar ElderLich

Bug Fix: Fix deck appearance preview and protector loading

Reuse loaded appearance previews so default items no longer appear last when switching tabs, skip missing premium mate icon variants without addressable errors, and load protector bundles in a stable order so protector materials render correctly again.
parent 9a186c05
......@@ -351,24 +351,39 @@ namespace MDPro3
if (!Directory.Exists(folder))
return null;
var files = Directory.GetFiles(folder);
var files = Directory.GetFiles(folder)
.OrderBy(path => Path.GetFileName(path).Equals(code, StringComparison.OrdinalIgnoreCase) ? 0 : 1)
.ThenBy(Path.GetFileName, StringComparer.OrdinalIgnoreCase)
.ToArray();
if (files.Length == 0)
return null;
var bundles = new List<AssetBundle>();
AssetBundle matAB = null;
List<AssetBundle> abs = new();
foreach (var file in files)
foreach (var path in files)
{
var ab = await AssetBundle.LoadFromFileAsync(file).WithCancellation(token);
abs.Add(ab);
if (Path.GetFileName(file) == code)
matAB = ab;
var bundle = await AssetBundle.LoadFromFileAsync(path).WithCancellation(token);
if (bundle == null)
continue;
bundles.Add(bundle);
if (Path.GetFileName(path).Equals(code, StringComparison.OrdinalIgnoreCase))
matAB = bundle;
}
if (matAB == null)
return null;
material = matAB.LoadAsset<Material>("PMat");
if (material == null)
{
foreach (var bundle in bundles)
bundle.Unload(false);
return null;
}
material.renderQueue = 3000;
foreach (var ab in abs)
ab.Unload(false);
foreach (var bundle in bundles)
bundle.Unload(false);
if (cachedPMat.ContainsKey(code))
material = cachedPMat[code];
......
......@@ -120,6 +120,7 @@ namespace MDPro3
private readonly Dictionary<int, string> descriptions = new();
private readonly Dictionary<int, string> categories = new();
private readonly Dictionary<string, Sprite> cachedIcons = new();
private readonly Dictionary<string, bool> iconAddressExists = new();
private string lastMat0;
private string lastMat1;
......@@ -517,6 +518,44 @@ namespace MDPro3
return returnValue;
}
private async UniTask<bool> HasItemIconAddress(string address)
{
if (string.IsNullOrEmpty(address))
return false;
lock (iconAddressExists)
if (iconAddressExists.TryGetValue(address, out var exists))
return exists;
var handle = Addressables.LoadResourceLocationsAsync(address, typeof(Sprite));
try
{
await handle.Task;
return handle.Result != null && handle.Result.Count > 0;
}
catch
{
return false;
}
finally
{
lock (iconAddressExists)
iconAddressExists[address] = handle.IsValid() && handle.Result != null && handle.Result.Count > 0;
if (handle.IsValid())
Addressables.Release(handle);
}
}
public async UniTask<Sprite> TryLoadItemIconAsync(string id, ItemType type)
{
var address = GetIconAddress(id);
if (!await HasItemIconAddress(address))
return null;
return await LoadItemIconAsync(id, type);
}
public async UniTask<Sprite> LoadConcreteItemIconAsync(string id, ItemType type, int player = 0)
{
if(id == CODE_RANDOM.ToString())
......
......@@ -139,6 +139,7 @@ namespace MDPro3.UI
loaded = true;
StartPremiumCrossfade();
PushLoadedPreviewToDetail();
}
catch (OperationCanceledException)
{
......@@ -160,7 +161,8 @@ namespace MDPro3.UI
base.CallToggleOnEvent();
CallHoverOnEvent();
Program.instance.appearance.GetUI<AppearanceUI>().Detail.SetItem(itemID, itemName, description, path == string.Empty);
var detail = Program.instance.appearance.GetUI<AppearanceUI>().Detail;
detail.SetItem(itemID, itemName, description, path == string.Empty, path, GetPreviewSprite(), GetPreviewMaterial());
Program.instance.appearance.GetUI<AppearanceUI>().SetHoverText(itemName);
Program.instance.appearance.lastSelectedItem = this;
......@@ -441,6 +443,36 @@ namespace MDPro3.UI
Destroy(gameObject);
}
private Sprite GetPreviewSprite()
{
if (!loaded)
return null;
if (path.StartsWith("Protector") || path.StartsWith("ProfileFrame"))
return null;
return Icon != null ? Icon.sprite : null;
}
private Material GetPreviewMaterial()
{
if (!loaded || !path.StartsWith("Protector"))
return null;
return protectorMaterial;
}
private void PushLoadedPreviewToDetail()
{
if (!isOn || Program.instance?.appearance == null)
return;
Program.instance.appearance.GetUI<AppearanceUI>().Detail.ApplyLoadedPreview(
itemID,
GetPreviewSprite(),
GetPreviewMaterial());
}
#region Premium Mate Crossfade
private void StartPremiumCrossfade()
......@@ -515,20 +547,13 @@ namespace MDPro3.UI
Sprite subSprite = null;
foreach (var variantId in rule.VariantIds)
{
var task = Program.items.LoadItemIconAsync(variantId.ToString(), Items.ItemType.Mate);
var task = Program.items.TryLoadItemIconAsync(variantId.ToString(), Items.ItemType.Mate);
while (task.Status == UniTaskStatus.Pending)
yield return null;
try
{
subSprite = task.GetAwaiter().GetResult();
if (subSprite != null)
break;
}
catch
{
// Icon not available for this variant, try next
}
subSprite = task.GetAwaiter().GetResult();
if (subSprite != null)
break;
}
if (subSprite == null || this == null || Icon == null)
......
......@@ -59,6 +59,9 @@ namespace MDPro3.UI
#endregion
private CancellationTokenSource cts;
private int currentCode = int.MinValue;
private bool currentIsCard;
private string currentPath = string.Empty;
public void Show()
{
......@@ -74,27 +77,65 @@ namespace MDPro3.UI
CG.blocksRaycasts = false;
}
public void SetItem(int code, string itemName, string desc, bool isCard)
public void SetItem(int code, string itemName, string desc, bool isCard, string path = null, Sprite preloadedSprite = null, Material preloadedMaterial = null)
{
TextSetting.text = itemName;
#if UNITY_EDITOR
TextSetting.text = $"{itemName} ({code})";
#endif
TextDescription.text = desc;
currentCode = code;
currentIsCard = isCard;
currentPath = path ?? string.Empty;
CancelLoading();
ResetPreview();
ApplyLoadedPreview(code, preloadedSprite, preloadedMaterial);
cts = new CancellationTokenSource();
_ = SetIconAsync(code, cts.Token, isCard);
}
public void ApplyLoadedPreview(int code, Sprite sprite = null, Material material = null)
{
if (code != currentCode)
return;
if (currentIsCard)
{
if (sprite == null)
return;
ResetPreview();
Image.sprite = sprite;
Image.gameObject.SetActive(true);
return;
}
if (currentPath.StartsWith("Protector"))
{
if (material == null)
return;
ResetPreview();
RawImage.material = material;
RawImage.gameObject.SetActive(true);
return;
}
if (currentPath.StartsWith("ProfileFrame") || sprite == null)
return;
ResetPreview();
Image.sprite = sprite;
Image.gameObject.SetActive(true);
WallpaperBG.gameObject.SetActive(currentPath.StartsWith("WallPaperIcon"));
}
private async UniTask SetIconAsync(int code, CancellationToken token, bool isCard)
{
var codeString = code.ToString();
Image.gameObject.SetActive(false);
Image.material = null;
RawImage.gameObject.SetActive(false);
WallpaperBG.gameObject.SetActive(false);
ResetPreview();
if (isCard) //Cross Duel Mate
{
......@@ -110,8 +151,11 @@ namespace MDPro3.UI
if (codeString.StartsWith("107")) // Protector
{
RawImage.material = await ABLoader.LoadProtectorMaterial(code.ToString(), token);
RawImage.material.renderQueue = 3000;
RawImage.gameObject.SetActive(true);
if (RawImage.material != null)
{
RawImage.material.renderQueue = 3000;
RawImage.gameObject.SetActive(true);
}
}
else
{
......@@ -149,6 +193,15 @@ namespace MDPro3.UI
}
}
private void ResetPreview()
{
Image.gameObject.SetActive(false);
Image.material = null;
RawImage.gameObject.SetActive(false);
RawImage.material = null;
WallpaperBG.gameObject.SetActive(false);
}
private void CancelLoading()
{
cts?.Cancel();
......@@ -156,4 +209,4 @@ namespace MDPro3.UI
cts = null;
}
}
}
\ No newline at end of file
}
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